diff --git a/.buildkite/pipeline-resource-definitions/_templates/_new_pipeline.yml b/.buildkite/pipeline-resource-definitions/_templates/_new_pipeline.yml index 6ef0d7652b96..877316ecdfd8 100644 --- a/.buildkite/pipeline-resource-definitions/_templates/_new_pipeline.yml +++ b/.buildkite/pipeline-resource-definitions/_templates/_new_pipeline.yml @@ -44,7 +44,6 @@ spec: repository: elastic/kibana # Point to a pipeline implementation, detailing the pipeline steps to run pipeline_file: .buildkite/pipelines/your-pipeline-name.yml - skip_intermediate_builds: false provider_settings: prefix_pull_request_fork_branch_names: false skip_pull_request_builds_for_existing_commits: true diff --git a/.buildkite/pipeline-resource-definitions/kibana-api-docs.yml b/.buildkite/pipeline-resource-definitions/kibana-api-docs.yml index 26ff7242dac6..168e24b01eaa 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-api-docs.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-api-docs.yml @@ -27,7 +27,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/build_api_docs.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/kibana-apis-capacity-testing-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-apis-capacity-testing-daily.yml index 244a0351de0b..787534984f63 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-apis-capacity-testing-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-apis-capacity-testing-daily.yml @@ -27,7 +27,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/scalability/api_capacity_testing_daily.yml - skip_intermediate_builds: false provider_settings: trigger_mode: none build_branches: true diff --git a/.buildkite/pipeline-resource-definitions/kibana-artifacts-snapshot.yml b/.buildkite/pipeline-resource-definitions/kibana-artifacts-snapshot.yml index f994f0cba33c..8d417739ef93 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-artifacts-snapshot.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-artifacts-snapshot.yml @@ -25,7 +25,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/artifacts.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/kibana-artifacts-staging.yml b/.buildkite/pipeline-resource-definitions/kibana-artifacts-staging.yml index 1d7b0488c7b3..28d4326cce38 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-artifacts-staging.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-artifacts-staging.yml @@ -25,7 +25,6 @@ spec: allow_rebuilds: true repository: elastic/kibana pipeline_file: .buildkite/pipelines/artifacts.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/kibana-artifacts-trigger.yml b/.buildkite/pipeline-resource-definitions/kibana-artifacts-trigger.yml index f08e505b9aab..51776700abf7 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-artifacts-trigger.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-artifacts-trigger.yml @@ -26,7 +26,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/artifacts_trigger.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/kibana-chrome-forward-testing.yml b/.buildkite/pipeline-resource-definitions/kibana-chrome-forward-testing.yml index 15265da35f39..b7c7c83f828d 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-chrome-forward-testing.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-chrome-forward-testing.yml @@ -27,7 +27,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/chrome_forward_testing.yml - skip_intermediate_builds: true provider_settings: prefix_pull_request_fork_branch_names: false skip_pull_request_builds_for_existing_commits: true diff --git a/.buildkite/pipeline-resource-definitions/kibana-coverage-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-coverage-daily.yml index 4192bb918658..67182739ddde 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-coverage-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-coverage-daily.yml @@ -29,7 +29,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/code_coverage/daily.yml - skip_intermediate_builds: false provider_settings: prefix_pull_request_fork_branch_names: false skip_pull_request_builds_for_existing_commits: true diff --git a/.buildkite/pipeline-resource-definitions/kibana-deploy-project.yml b/.buildkite/pipeline-resource-definitions/kibana-deploy-project.yml index 490c9d9afc4e..f098ff82f322 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-deploy-project.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-deploy-project.yml @@ -26,7 +26,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/serverless_deployment/project-build-and-deploy-pr.yml - skip_intermediate_builds: true provider_settings: build_pull_requests: true prefix_pull_request_fork_branch_names: false diff --git a/.buildkite/pipeline-resource-definitions/kibana-es-forward-testing.yml b/.buildkite/pipeline-resource-definitions/kibana-es-forward-testing.yml index fa4ee2d26387..27549d37a66a 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-es-forward-testing.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-es-forward-testing.yml @@ -27,7 +27,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/es_forward.yml # Note: this file exists in 7.17 only - skip_intermediate_builds: false provider_settings: prefix_pull_request_fork_branch_names: false trigger_mode: none diff --git a/.buildkite/pipeline-resource-definitions/kibana-es-serverless-snapshots.yml b/.buildkite/pipeline-resource-definitions/kibana-es-serverless-snapshots.yml index 6ba182ccd393..de60f5311669 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-es-serverless-snapshots.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-es-serverless-snapshots.yml @@ -28,7 +28,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/es_serverless/verify_es_serverless_image.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml b/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml index b99fd82408b7..652ce7b35c30 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-es-snapshots.yml @@ -26,7 +26,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/es_snapshots/build.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false @@ -96,7 +95,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/es_snapshots/promote.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false @@ -146,7 +144,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/es_snapshots/verify.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/kibana-esql-grammar-sync.yml b/.buildkite/pipeline-resource-definitions/kibana-esql-grammar-sync.yml index 8cc4b54a5ce0..d2259c7cf769 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-esql-grammar-sync.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-esql-grammar-sync.yml @@ -26,7 +26,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/esql_grammar_sync.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/kibana-flaky.yml b/.buildkite/pipeline-resource-definitions/kibana-flaky.yml index f1c348e05920..e4a840fd89d7 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-flaky.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-flaky.yml @@ -22,7 +22,6 @@ spec: default_branch: refs/pull/INSERT_PR_NUMBER/head repository: elastic/kibana pipeline_file: .buildkite/pipelines/flaky_tests/pipeline.sh - skip_intermediate_builds: false provider_settings: build_branches: true build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/kibana-fleet-packages-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-fleet-packages-daily.yml index d948460513c8..cb8e0143cb24 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-fleet-packages-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-fleet-packages-daily.yml @@ -26,7 +26,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/fleet/packages_daily.yml - skip_intermediate_builds: false provider_settings: trigger_mode: none publish_commit_status: false diff --git a/.buildkite/pipeline-resource-definitions/kibana-performance-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-performance-daily.yml index 915cce93a248..166b8119edd6 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-performance-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-performance-daily.yml @@ -27,7 +27,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/performance/daily.yml - skip_intermediate_builds: false provider_settings: trigger_mode: none build_branches: true diff --git a/.buildkite/pipeline-resource-definitions/kibana-pr.yml b/.buildkite/pipeline-resource-definitions/kibana-pr.yml index 0f5246106ac4..19f05ef012b0 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-pr.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-pr.yml @@ -29,7 +29,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/scripts/pipelines/pull_request/pipeline.sh - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: true diff --git a/.buildkite/pipeline-resource-definitions/kibana-purge-cloud-deployments.yml b/.buildkite/pipeline-resource-definitions/kibana-purge-cloud-deployments.yml index 9124d001d6f7..d7d35b8f8d5d 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-purge-cloud-deployments.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-purge-cloud-deployments.yml @@ -26,7 +26,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/purge_cloud_deployments.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/kibana-serverless-release-testing.yml b/.buildkite/pipeline-resource-definitions/kibana-serverless-release-testing.yml index 5276871fa1c9..84c15018933a 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-serverless-release-testing.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-serverless-release-testing.yml @@ -26,7 +26,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/es_serverless/emergency_release_branch_testing.yml - skip_intermediate_builds: false provider_settings: build_branches: true build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/kibana-serverless-release.yml b/.buildkite/pipeline-resource-definitions/kibana-serverless-release.yml index e1457f10420f..568ed8ba2b16 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-serverless-release.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-serverless-release.yml @@ -23,7 +23,6 @@ spec: ELASTIC_SLACK_NOTIFICATIONS_ENABLED: 'true' default_branch: main allow_rebuilds: false - skip_intermediate_builds: false repository: elastic/kibana pipeline_file: .buildkite/pipelines/serverless_deployment/run_serverless_release_assistant.yml provider_settings: diff --git a/.buildkite/pipeline-resource-definitions/kibana-vm-images.yml b/.buildkite/pipeline-resource-definitions/kibana-vm-images.yml index dd8a6c945c45..c0ca615646e9 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-vm-images.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-vm-images.yml @@ -24,7 +24,6 @@ spec: default_branch: main repository: elastic/ci-agent-images pipeline_file: vm-images/.buildkite/pipeline.yml - skip_intermediate_builds: false provider_settings: trigger_mode: none schedules: diff --git a/.buildkite/pipeline-resource-definitions/scalability_testing-daily.yml b/.buildkite/pipeline-resource-definitions/scalability_testing-daily.yml index 162bb6220ea1..48dfd711cec7 100644 --- a/.buildkite/pipeline-resource-definitions/scalability_testing-daily.yml +++ b/.buildkite/pipeline-resource-definitions/scalability_testing-daily.yml @@ -27,7 +27,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/pipelines/scalability/daily.yml - skip_intermediate_builds: false provider_settings: trigger_mode: none build_branches: true diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-defend-workflows.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-defend-workflows.yml index d4d2541f1c4a..3aa82698ee52 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-defend-workflows.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-defend-workflows.yml @@ -17,7 +17,6 @@ spec: spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_defend_workflows.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-detection-engine.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-detection-engine.yml index 77361eed441e..4d8265664d0d 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-detection-engine.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-detection-engine.yml @@ -17,7 +17,6 @@ spec: spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_detection_engine.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-entity-analytics.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-entity-analytics.yml index 49338bf7b6d3..9297f4c6411f 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-entity-analytics.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-entity-analytics.yml @@ -17,7 +17,6 @@ spec: spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_entity_analytics.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-explore.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-explore.yml index ee8cf00a755f..1ac5f46d5610 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-explore.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-explore.yml @@ -17,7 +17,6 @@ spec: spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_explore.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-gen-ai.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-gen-ai.yml index f22e321176eb..7bf3f50d5017 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-gen-ai.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-gen-ai.yml @@ -17,7 +17,6 @@ spec: spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_gen_ai.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-investigations.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-investigations.yml index 7de3b5f8cc28..dd16077339d9 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-investigations.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-investigations.yml @@ -17,7 +17,6 @@ spec: spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_investigations.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-rule-management.yml b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-rule-management.yml index 4f095294f442..ee9147c90563 100644 --- a/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-rule-management.yml +++ b/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-rule-management.yml @@ -17,7 +17,6 @@ spec: spec: repository: elastic/kibana pipeline_file: .buildkite/pipelines/security_solution_quality_gate/mki_security_solution_rule_management.yml - skip_intermediate_builds: false provider_settings: build_branches: false build_pull_requests: false diff --git a/.buildkite/pipeline-resource-definitions/trigger-version-dependent-jobs.yml b/.buildkite/pipeline-resource-definitions/trigger-version-dependent-jobs.yml index 8dd486c3176c..dce527f9e7f6 100644 --- a/.buildkite/pipeline-resource-definitions/trigger-version-dependent-jobs.yml +++ b/.buildkite/pipeline-resource-definitions/trigger-version-dependent-jobs.yml @@ -31,7 +31,6 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/scripts/pipelines/trigger_version_dependent_jobs/pipeline.sh - skip_intermediate_builds: false provider_settings: prefix_pull_request_fork_branch_names: false skip_pull_request_builds_for_existing_commits: true diff --git a/.buildkite/pipelines/chrome_forward_testing.yml b/.buildkite/pipelines/chrome_forward_testing.yml index eb80625a73d7..965f910e8e07 100644 --- a/.buildkite/pipelines/chrome_forward_testing.yml +++ b/.buildkite/pipelines/chrome_forward_testing.yml @@ -20,9 +20,9 @@ steps: - wait - command: .buildkite/scripts/steps/build_kibana.sh - label: Build Kibana Distribution and Plugins + label: Build Kibana Distribution agents: - machineType: n2-standard-16 + machineType: n2-standard-8 preemptible: true key: build timeout_in_minutes: 60 diff --git a/.buildkite/pipelines/es_serverless/verify_es_serverless_image.yml b/.buildkite/pipelines/es_serverless/verify_es_serverless_image.yml index fa8162ca93c0..3058293bae79 100644 --- a/.buildkite/pipelines/es_serverless/verify_es_serverless_image.yml +++ b/.buildkite/pipelines/es_serverless/verify_es_serverless_image.yml @@ -31,13 +31,13 @@ steps: provider: gcp machineType: n2-standard-2 - - label: "Build Kibana Distribution and Plugins" + - label: "Build Kibana Distribution" command: .buildkite/scripts/steps/build_kibana.sh agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod provider: gcp - machineType: n2-standard-16 + machineType: n2-standard-8 key: build if: "build.env('KIBANA_BUILD_ID') == null || build.env('KIBANA_BUILD_ID') == ''" depends_on: pre-build diff --git a/.buildkite/pipelines/es_snapshots/verify.yml b/.buildkite/pipelines/es_snapshots/verify.yml index d91af527c826..e8c9899e9aed 100755 --- a/.buildkite/pipelines/es_snapshots/verify.yml +++ b/.buildkite/pipelines/es_snapshots/verify.yml @@ -23,12 +23,12 @@ steps: - wait - command: .buildkite/scripts/steps/build_kibana.sh - label: Build Kibana Distribution and Plugins + label: Build Kibana Distribution agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod provider: gcp - machineType: n2-standard-16 + machineType: n2-standard-8 preemptible: true key: build if: "build.env('KIBANA_BUILD_ID') == null || build.env('KIBANA_BUILD_ID') == ''" diff --git a/.buildkite/pipelines/fips.yml b/.buildkite/pipelines/fips.yml index 09ae10496456..f4a5b3623bbc 100644 --- a/.buildkite/pipelines/fips.yml +++ b/.buildkite/pipelines/fips.yml @@ -17,9 +17,9 @@ steps: - wait - command: .buildkite/scripts/steps/build_kibana.sh - label: Build Kibana Distribution and Plugins + label: Build Kibana Distribution agents: - machineType: n2-standard-16 + machineType: n2-standard-8 preemptible: true key: build if: "build.env('KIBANA_BUILD_ID') == null || build.env('KIBANA_BUILD_ID') == ''" diff --git a/.buildkite/pipelines/flaky_tests/pipeline.ts b/.buildkite/pipelines/flaky_tests/pipeline.ts index ec1b4994beae..0d6c3b5c40f7 100644 --- a/.buildkite/pipelines/flaky_tests/pipeline.ts +++ b/.buildkite/pipelines/flaky_tests/pipeline.ts @@ -122,7 +122,7 @@ const pipeline = { steps.push({ command: '.buildkite/scripts/steps/build_kibana.sh', - label: 'Build Kibana Distribution and Plugins', + label: 'Build Kibana Distribution', agents: expandAgentQueue('c2-8'), key: 'build', if: "build.env('KIBANA_BUILD_ID') == null || build.env('KIBANA_BUILD_ID') == ''", diff --git a/.buildkite/pipelines/on_merge.yml b/.buildkite/pipelines/on_merge.yml index 65c7f0095f06..e5d28465b2dc 100644 --- a/.buildkite/pipelines/on_merge.yml +++ b/.buildkite/pipelines/on_merge.yml @@ -17,12 +17,12 @@ steps: - wait - command: .buildkite/scripts/steps/on_merge_build_and_metrics.sh - label: Build Kibana Distribution and Plugins + label: Build Kibana Distribution agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod provider: gcp - machineType: n2-standard-16 + machineType: n2-standard-8 preemptible: true key: build timeout_in_minutes: 60 diff --git a/.buildkite/pipelines/on_merge_unsupported_ftrs.yml b/.buildkite/pipelines/on_merge_unsupported_ftrs.yml index cf1a523be5a3..a7800fcc92dc 100644 --- a/.buildkite/pipelines/on_merge_unsupported_ftrs.yml +++ b/.buildkite/pipelines/on_merge_unsupported_ftrs.yml @@ -13,12 +13,12 @@ steps: limit: 1 - command: .buildkite/scripts/steps/build_kibana.sh - label: Build Kibana Distribution and Plugins + label: Build Kibana Distribution agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod provider: gcp - machineType: n2-standard-16 + machineType: n2-standard-8 preemptible: true key: build if: "build.env('KIBANA_BUILD_ID') == null || build.env('KIBANA_BUILD_ID') == ''" diff --git a/.buildkite/pipelines/performance/daily.yml b/.buildkite/pipelines/performance/daily.yml index bbbdde955df7..1eeb044304d2 100644 --- a/.buildkite/pipelines/performance/daily.yml +++ b/.buildkite/pipelines/performance/daily.yml @@ -9,13 +9,13 @@ steps: - wait - - label: '🧑‍🏭 Build Kibana Distribution and Plugins' + - label: '🧑‍🏭 Build Kibana Distribution' command: .buildkite/scripts/steps/build_kibana.sh agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod provider: gcp - machineType: c2-standard-16 + machineType: n2-standard-8 key: build if: "build.env('KIBANA_BUILD_ID') == null || build.env('KIBANA_BUILD_ID') == ''" diff --git a/.buildkite/pipelines/performance/data_set_extraction_daily.yml b/.buildkite/pipelines/performance/data_set_extraction_daily.yml index bb2c33f7a2d3..dcb735531896 100644 --- a/.buildkite/pipelines/performance/data_set_extraction_daily.yml +++ b/.buildkite/pipelines/performance/data_set_extraction_daily.yml @@ -10,13 +10,13 @@ steps: - wait - - label: ':building_construction: Build Kibana Distribution and Plugins' + - label: ':building_construction: Build Kibana Distribution ' command: .buildkite/scripts/steps/build_kibana.sh agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod provider: gcp - machineType: c2-standard-16 + machineType: n2-standard-8 key: build if: "build.env('KIBANA_BUILD_ID') == null || build.env('KIBANA_BUILD_ID') == ''" diff --git a/.buildkite/pipelines/pull_request/base.yml b/.buildkite/pipelines/pull_request/base.yml index e7b593f464b5..f56159882b2a 100644 --- a/.buildkite/pipelines/pull_request/base.yml +++ b/.buildkite/pipelines/pull_request/base.yml @@ -8,9 +8,9 @@ steps: - wait - command: .buildkite/scripts/steps/build_kibana.sh - label: Build Kibana Distribution and Plugins + label: Build Kibana Distribution agents: - machineType: n2-standard-16 + machineType: n2-standard-8 preemptible: true key: build if: "build.env('KIBANA_BUILD_ID') == null || build.env('KIBANA_BUILD_ID') == ''" diff --git a/.buildkite/pipelines/scalability/api_capacity_testing_daily.yml b/.buildkite/pipelines/scalability/api_capacity_testing_daily.yml index 785726bf9517..909329234c32 100644 --- a/.buildkite/pipelines/scalability/api_capacity_testing_daily.yml +++ b/.buildkite/pipelines/scalability/api_capacity_testing_daily.yml @@ -9,13 +9,13 @@ steps: - wait - - label: 'Build Kibana Distribution and Plugins' + - label: 'Build Kibana Distribution' command: .buildkite/scripts/steps/build_kibana.sh agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod provider: gcp - machineType: n2-standard-16 + machineType: n2-standard-8 preemptible: true key: build if: "build.env('KIBANA_BUILD_ID') == null || build.env('KIBANA_BUILD_ID') == ''" diff --git a/.buildkite/pipelines/security_solution_quality_gate/mki_quality_gate/mki_quality_gate_detection_engine.yml b/.buildkite/pipelines/security_solution_quality_gate/mki_quality_gate/mki_quality_gate_detection_engine.yml index de98c0ffffd3..5bf1430faf5a 100644 --- a/.buildkite/pipelines/security_solution_quality_gate/mki_quality_gate/mki_quality_gate_detection_engine.yml +++ b/.buildkite/pipelines/security_solution_quality_gate/mki_quality_gate/mki_quality_gate_detection_engine.yml @@ -61,9 +61,9 @@ steps: - exit_status: '1' limit: 2 - - label: Running exception_lists:common:lists:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_lists:common:lists:qa:serverless:release - key: exception_lists:common:lists:qa:serverless:release + - label: Running exception_lists:auth:common:qa:serverless:release + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_lists:auth:common:qa:serverless:release + key: exception_lists:auth:common:qa:serverless:release agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod @@ -75,9 +75,9 @@ steps: - exit_status: '1' limit: 2 - - label: Running exception_lists:items:lists:qa:serverless:release - command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_lists:items:lists:qa:serverless:release - key: exception_lists:items:lists:qa:serverless:release + - label: Running exception_lists:auth:items:qa:serverless + command: .buildkite/scripts/pipelines/security_solution_quality_gate/api_integration/api-integration-tests.sh exception_lists:auth:items:qa:serverless + key: exception_lists:auth:items:qa:serverless agents: image: family/kibana-ubuntu-2004 imageProject: elastic-images-prod diff --git a/.buildkite/scripts/build_kibana_plugins.sh b/.buildkite/scripts/build_kibana_plugins.sh deleted file mode 100755 index 4e566008b335..000000000000 --- a/.buildkite/scripts/build_kibana_plugins.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -echo "--- Build Platform Plugins" -THREADS=$(grep -c ^processor /proc/cpuinfo) -node scripts/build_kibana_platform_plugins --examples --test-plugins --workers "$THREADS" --no-inspect-workers --no-progress diff --git a/.buildkite/scripts/download_build_artifacts.sh b/.buildkite/scripts/download_build_artifacts.sh index 1b52e82c2d66..497efa181018 100755 --- a/.buildkite/scripts/download_build_artifacts.sh +++ b/.buildkite/scripts/download_build_artifacts.sh @@ -6,12 +6,11 @@ source "$(dirname "$0")/common/util.sh" if [[ "${KIBANA_BUILD_ID:-}" != "false" ]]; then if [[ ! -d "$KIBANA_BUILD_LOCATION/bin" ]]; then - echo '--- Downloading Distribution and Plugin artifacts' + echo '--- Downloading Distribution' cd "$WORKSPACE" download_artifact kibana-default.tar.gz . --build "${KIBANA_BUILD_ID:-$BUILDKITE_BUILD_ID}" - download_artifact kibana-default-plugins.tar.gz . --build "${KIBANA_BUILD_ID:-$BUILDKITE_BUILD_ID}" mkdir -p "$KIBANA_BUILD_LOCATION" tar -xzf kibana-default.tar.gz -C "$KIBANA_BUILD_LOCATION" --strip=1 @@ -24,7 +23,5 @@ if [[ "${KIBANA_BUILD_ID:-}" != "false" ]]; then fi cd "$KIBANA_DIR" - - tar -xzf ../kibana-default-plugins.tar.gz fi fi diff --git a/.buildkite/scripts/post_build_kibana_plugins.sh b/.buildkite/scripts/post_build_kibana_plugins.sh deleted file mode 100755 index 288fd262cafa..000000000000 --- a/.buildkite/scripts/post_build_kibana_plugins.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -echo "--- Archive built plugins" -shopt -s globstar -tar -zcf \ - target/kibana-default-plugins.tar.gz \ - x-pack/plugins/**/target/public \ - x-pack/test/**/target/public \ - examples/**/target/public \ - x-pack/examples/**/target/public \ - test/**/target/public diff --git a/.buildkite/scripts/steps/build_kibana.sh b/.buildkite/scripts/steps/build_kibana.sh index bf4a9ff243d0..4bad332dd073 100755 --- a/.buildkite/scripts/steps/build_kibana.sh +++ b/.buildkite/scripts/steps/build_kibana.sh @@ -4,6 +4,4 @@ set -euo pipefail .buildkite/scripts/bootstrap.sh .buildkite/scripts/build_kibana.sh -.buildkite/scripts/build_kibana_plugins.sh -.buildkite/scripts/post_build_kibana_plugins.sh .buildkite/scripts/post_build_kibana.sh diff --git a/.buildkite/scripts/steps/es_serverless/promote_es_serverless_image.sh b/.buildkite/scripts/steps/es_serverless/promote_es_serverless_image.sh index df58d534bb4f..4598e03b1cdb 100755 --- a/.buildkite/scripts/steps/es_serverless/promote_es_serverless_image.sh +++ b/.buildkite/scripts/steps/es_serverless/promote_es_serverless_image.sh @@ -77,5 +77,6 @@ steps: async: true build: env: - IMAGES_CONFIG="kibana/images.yml" + IMAGES_CONFIG: "kibana/images.yml" + RETRY: "1" EOF diff --git a/.buildkite/scripts/steps/es_snapshots/promote.sh b/.buildkite/scripts/steps/es_snapshots/promote.sh index 7028cafd6e3f..d09ef2d2420a 100755 --- a/.buildkite/scripts/steps/es_snapshots/promote.sh +++ b/.buildkite/scripts/steps/es_snapshots/promote.sh @@ -23,6 +23,7 @@ steps: async: true build: env: - IMAGES_CONFIG="kibana/images.yml" + IMAGES_CONFIG: "kibana/images.yml" + RETRY: "1" EOF fi diff --git a/.buildkite/scripts/steps/functional/defend_workflows_burn.sh b/.buildkite/scripts/steps/functional/defend_workflows_burn.sh index 6a97ba4e82b3..44d87ba4a663 100644 --- a/.buildkite/scripts/steps/functional/defend_workflows_burn.sh +++ b/.buildkite/scripts/steps/functional/defend_workflows_burn.sh @@ -4,10 +4,7 @@ set -euo pipefail source .buildkite/scripts/steps/functional/common.sh -.buildkite/scripts/bootstrap.sh -.buildkite/scripts/copy_es_snapshot_cache.sh -node scripts/build_kibana_platform_plugins.js - +export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} export JOB=kibana-defend-workflows-cypress buildkite-agent meta-data set "${BUILDKITE_JOB_ID}_is_test_execution_step" 'false' diff --git a/.buildkite/scripts/steps/functional/defend_workflows_serverless_burn.sh b/.buildkite/scripts/steps/functional/defend_workflows_serverless_burn.sh index 4bebee15953e..a092ffbd4186 100644 --- a/.buildkite/scripts/steps/functional/defend_workflows_serverless_burn.sh +++ b/.buildkite/scripts/steps/functional/defend_workflows_serverless_burn.sh @@ -4,10 +4,7 @@ set -euo pipefail source .buildkite/scripts/steps/functional/common.sh -.buildkite/scripts/bootstrap.sh -.buildkite/scripts/copy_es_snapshot_cache.sh -node scripts/build_kibana_platform_plugins.js - +export KIBANA_INSTALL_DIR=${KIBANA_BUILD_LOCATION} export JOB=kibana-defend-workflows-serverless-cypress buildkite-agent meta-data set "${BUILDKITE_JOB_ID}_is_test_execution_step" 'false' diff --git a/.buildkite/scripts/steps/on_merge_build_and_metrics.sh b/.buildkite/scripts/steps/on_merge_build_and_metrics.sh index fb05bb99b0c5..1f1e492f87be 100755 --- a/.buildkite/scripts/steps/on_merge_build_and_metrics.sh +++ b/.buildkite/scripts/steps/on_merge_build_and_metrics.sh @@ -4,7 +4,5 @@ set -euo pipefail .buildkite/scripts/bootstrap.sh .buildkite/scripts/build_kibana.sh -.buildkite/scripts/build_kibana_plugins.sh -.buildkite/scripts/post_build_kibana_plugins.sh .buildkite/scripts/post_build_kibana.sh .buildkite/scripts/saved_object_field_metrics.sh diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6dc2aa32a79a..ef265cf7c569 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -766,6 +766,7 @@ x-pack/examples/triggers_actions_ui_example @elastic/response-ops x-pack/examples/ui_actions_enhanced_examples @elastic/appex-sharedux x-pack/packages/ai-infra/inference-common @elastic/appex-ai-infra x-pack/packages/ai-infra/product-doc-artifact-builder @elastic/appex-ai-infra +x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared @elastic/kibana-management x-pack/packages/index-management/index_management_shared_types @elastic/kibana-management x-pack/packages/kbn-ai-assistant @elastic/search-kibana x-pack/packages/kbn-ai-assistant-common @elastic/search-kibana @@ -1189,6 +1190,7 @@ x-pack/test_serverless/**/test_suites/observability/ai_assistant @elastic/obs-ai /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/api_integration/deployment_agnostic/apis/observability/infra @elastic/obs-ux-logs-team +/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm @elastic/obs-ux-logs-team ## Logs UI code exceptions -> @elastic/obs-ux-logs-team /x-pack/test_serverless/functional/page_objects/svl_oblt_onboarding_stream_log_file.ts @elastic/obs-ux-logs-team @@ -1842,7 +1844,6 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/plugins/security_solution/public/detection_engine/rule_management_ui @elastic/security-detection-rule-management /x-pack/plugins/security_solution/public/detection_engine/rule_monitoring @elastic/security-detection-rule-management /x-pack/plugins/security_solution/public/detections/components/callouts @elastic/security-detection-rule-management -/x-pack/plugins/security_solution/public/detections/components/modals/ml_job_upgrade_modal @elastic/security-detection-rule-management /x-pack/plugins/security_solution/public/detections/components/rules @elastic/security-detection-rule-management /x-pack/plugins/security_solution/public/detections/components/rules/rule_preview @elastic/security-detection-engine /x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules @elastic/security-detection-rule-management diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 2d0938a5f3e7..8213690c68bb 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index fe9de10c7caf..6ff23feb1abe 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-06 +date: 2024-11-12 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 a52b1bfcfe11..903d7bb8564d 100644 --- a/api_docs/ai_assistant_management_selection.mdx +++ b/api_docs/ai_assistant_management_selection.mdx @@ -8,7 +8,7 @@ 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementSelection'] --- import aiAssistantManagementSelectionObj from './ai_assistant_management_selection.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 044a29123d58..2dbb911712af 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 8f6588d9b4fb..f1c95bf42eee 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-06 +date: 2024-11-12 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 c175c1a53d2e..d0518c5574ce 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/apm_data_access.mdx b/api_docs/apm_data_access.mdx index 8577e434ee12..76949f438879 100644 --- a/api_docs/apm_data_access.mdx +++ b/api_docs/apm_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apmDataAccess title: "apmDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the apmDataAccess plugin -date: 2024-11-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index cb28fdaa0ed0..4c8900cf3582 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-06 +date: 2024-11-12 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 000ea07f5180..a9e8cc610f7b 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-06 +date: 2024-11-12 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 b705eff254f7..477390c3afae 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-06 +date: 2024-11-12 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 90490722bc9e..dd96643533e4 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-06 +date: 2024-11-12 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 5222b22b37cd..52e0f0e1b1e7 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-06 +date: 2024-11-12 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 e9d89fc39abc..05c7d8e00488 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-06 +date: 2024-11-12 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 99c2ac838883..edb6f7038849 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-06 +date: 2024-11-12 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 c0ccd079cd3b..3d811c99930f 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-06 +date: 2024-11-12 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 d62735d5755e..eb5333457325 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-06 +date: 2024-11-12 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 12c5f75c080f..0d6bbaaeed5f 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-06 +date: 2024-11-12 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 5ccee0d0d76a..458f4f5f7107 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; diff --git a/api_docs/controls.devdocs.json b/api_docs/controls.devdocs.json index edd1e4198cb5..5a0a3ae38133 100644 --- a/api_docs/controls.devdocs.json +++ b/api_docs/controls.devdocs.json @@ -571,7 +571,7 @@ "label": "labelPosition", "description": [], "signature": [ - "\"twoLine\" | \"oneLine\"" + "\"oneLine\" | \"twoLine\"" ], "path": "src/plugins/controls/common/control_group/types.ts", "deprecated": false, @@ -669,7 +669,7 @@ "section": "def-common.ControlGroupSerializedState", "text": "ControlGroupSerializedState" }, - " extends Pick<", + " extends Omit<", { "pluginId": "controls", "scope": "common", @@ -685,7 +685,7 @@ "section": "def-common.DefaultControlState", "text": "DefaultControlState" }, - ">, \"chainingSystem\" | \"editorConfig\">" + ">, \"initialChildControlState\">" ], "path": "src/plugins/controls/common/control_group/types.ts", "deprecated": false, @@ -693,49 +693,21 @@ "children": [ { "parentPluginId": "controls", - "id": "def-public.ControlGroupSerializedState.panelsJSON", - "type": "string", - "tags": [], - "label": "panelsJSON", - "description": [], - "path": "src/plugins/controls/common/control_group/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "controls", - "id": "def-public.ControlGroupSerializedState.ignoreParentSettingsJSON", - "type": "string", - "tags": [], - "label": "ignoreParentSettingsJSON", - "description": [], - "path": "src/plugins/controls/common/control_group/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "controls", - "id": "def-public.ControlGroupSerializedState.controlStyle", - "type": "CompoundType", - "tags": [], - "label": "controlStyle", - "description": [], - "signature": [ - "\"twoLine\" | \"oneLine\"" - ], - "path": "src/plugins/controls/common/control_group/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "controls", - "id": "def-public.ControlGroupSerializedState.showApplySelections", - "type": "CompoundType", + "id": "def-public.ControlGroupSerializedState.controls", + "type": "Array", "tags": [], - "label": "showApplySelections", + "label": "controls", "description": [], "signature": [ - "boolean | undefined" + "(", + { + "pluginId": "controls", + "scope": "common", + "docId": "kibControlsPluginApi", + "section": "def-common.DefaultControlState", + "text": "DefaultControlState" + }, + " & { type: string; order: number; } & { id?: string | undefined; })[]" ], "path": "src/plugins/controls/common/control_group/types.ts", "deprecated": false, @@ -2438,20 +2410,14 @@ "functions": [ { "parentPluginId": "controls", - "id": "def-server.controlGroupSerializedStateToSerializableRuntimeState", + "id": "def-server.controlGroupSavedObjectStateToSerializableRuntimeState", "type": "Function", "tags": [], - "label": "controlGroupSerializedStateToSerializableRuntimeState", + "label": "controlGroupSavedObjectStateToSerializableRuntimeState", "description": [], "signature": [ - "(serializedState: ", - { - "pluginId": "controls", - "scope": "common", - "docId": "kibControlsPluginApi", - "section": "def-common.ControlGroupSerializedState", - "text": "ControlGroupSerializedState" - }, + "(savedObjectState: ", + "ControlGroupSavedObjectState", ") => ", "SerializableControlGroupState" ], @@ -2461,19 +2427,13 @@ "children": [ { "parentPluginId": "controls", - "id": "def-server.controlGroupSerializedStateToSerializableRuntimeState.$1", - "type": "Object", + "id": "def-server.controlGroupSavedObjectStateToSerializableRuntimeState.$1", + "type": "CompoundType", "tags": [], - "label": "serializedState", + "label": "savedObjectState", "description": [], "signature": [ - { - "pluginId": "controls", - "scope": "common", - "docId": "kibControlsPluginApi", - "section": "def-common.ControlGroupSerializedState", - "text": "ControlGroupSerializedState" - } + "ControlGroupSavedObjectState" ], "path": "src/plugins/controls/server/control_group/control_group_persistence.ts", "deprecated": false, @@ -2526,10 +2486,10 @@ }, { "parentPluginId": "controls", - "id": "def-server.serializableRuntimeStateToControlGroupSerializedState", + "id": "def-server.serializableRuntimeStateToControlGroupSavedObjectState", "type": "Function", "tags": [], - "label": "serializableRuntimeStateToControlGroupSerializedState", + "label": "serializableRuntimeStateToControlGroupSavedObjectState", "description": [], "signature": [ "(serializable: ", @@ -2541,13 +2501,7 @@ "text": "SerializableRecord" }, ") => ", - { - "pluginId": "controls", - "scope": "common", - "docId": "kibControlsPluginApi", - "section": "def-common.ControlGroupSerializedState", - "text": "ControlGroupSerializedState" - } + "ControlGroupSavedObjectState" ], "path": "src/plugins/controls/server/control_group/control_group_persistence.ts", "deprecated": false, @@ -2555,7 +2509,7 @@ "children": [ { "parentPluginId": "controls", - "id": "def-server.serializableRuntimeStateToControlGroupSerializedState.$1", + "id": "def-server.serializableRuntimeStateToControlGroupSavedObjectState.$1", "type": "Object", "tags": [], "label": "serializable", @@ -2587,7 +2541,7 @@ "tags": [], "label": "ControlGroupTelemetry", "description": [], - "path": "src/plugins/controls/server/control_group/control_group_telemetry.ts", + "path": "src/plugins/controls/server/control_group/types.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -2598,7 +2552,7 @@ "tags": [], "label": "total", "description": [], - "path": "src/plugins/controls/server/control_group/control_group_telemetry.ts", + "path": "src/plugins/controls/server/control_group/types.ts", "deprecated": false, "trackAdoption": false }, @@ -2612,7 +2566,7 @@ "signature": [ "{ [key: string]: number; }" ], - "path": "src/plugins/controls/server/control_group/control_group_telemetry.ts", + "path": "src/plugins/controls/server/control_group/types.ts", "deprecated": false, "trackAdoption": false }, @@ -2626,7 +2580,7 @@ "signature": [ "{ [key: string]: number; }" ], - "path": "src/plugins/controls/server/control_group/control_group_telemetry.ts", + "path": "src/plugins/controls/server/control_group/types.ts", "deprecated": false, "trackAdoption": false }, @@ -2640,7 +2594,7 @@ "signature": [ "{ [key: string]: number; }" ], - "path": "src/plugins/controls/server/control_group/control_group_telemetry.ts", + "path": "src/plugins/controls/server/control_group/types.ts", "deprecated": false, "trackAdoption": false }, @@ -2654,7 +2608,7 @@ "signature": [ "{ [key: string]: { total: number; details: { [key: string]: number; }; }; }" ], - "path": "src/plugins/controls/server/control_group/control_group_telemetry.ts", + "path": "src/plugins/controls/server/control_group/types.ts", "deprecated": false, "trackAdoption": false } @@ -2786,7 +2740,7 @@ "label": "labelPosition", "description": [], "signature": [ - "\"twoLine\" | \"oneLine\"" + "\"oneLine\" | \"twoLine\"" ], "path": "src/plugins/controls/common/control_group/types.ts", "deprecated": false, @@ -2884,7 +2838,7 @@ "section": "def-common.ControlGroupSerializedState", "text": "ControlGroupSerializedState" }, - " extends Pick<", + " extends Omit<", { "pluginId": "controls", "scope": "common", @@ -2900,7 +2854,7 @@ "section": "def-common.DefaultControlState", "text": "DefaultControlState" }, - ">, \"chainingSystem\" | \"editorConfig\">" + ">, \"initialChildControlState\">" ], "path": "src/plugins/controls/common/control_group/types.ts", "deprecated": false, @@ -2908,49 +2862,21 @@ "children": [ { "parentPluginId": "controls", - "id": "def-common.ControlGroupSerializedState.panelsJSON", - "type": "string", - "tags": [], - "label": "panelsJSON", - "description": [], - "path": "src/plugins/controls/common/control_group/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "controls", - "id": "def-common.ControlGroupSerializedState.ignoreParentSettingsJSON", - "type": "string", - "tags": [], - "label": "ignoreParentSettingsJSON", - "description": [], - "path": "src/plugins/controls/common/control_group/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "controls", - "id": "def-common.ControlGroupSerializedState.controlStyle", - "type": "CompoundType", - "tags": [], - "label": "controlStyle", - "description": [], - "signature": [ - "\"twoLine\" | \"oneLine\"" - ], - "path": "src/plugins/controls/common/control_group/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "controls", - "id": "def-common.ControlGroupSerializedState.showApplySelections", - "type": "CompoundType", + "id": "def-common.ControlGroupSerializedState.controls", + "type": "Array", "tags": [], - "label": "showApplySelections", + "label": "controls", "description": [], "signature": [ - "boolean | undefined" + "(", + { + "pluginId": "controls", + "scope": "common", + "docId": "kibControlsPluginApi", + "section": "def-common.DefaultControlState", + "text": "DefaultControlState" + }, + " & { type: string; order: number; } & { id?: string | undefined; })[]" ], "path": "src/plugins/controls/common/control_group/types.ts", "deprecated": false, @@ -3130,6 +3056,23 @@ "tags": [], "label": "ParentIgnoreSettings", "description": [], + "signature": [ + { + "pluginId": "controls", + "scope": "common", + "docId": "kibControlsPluginApi", + "section": "def-common.ParentIgnoreSettings", + "text": "ParentIgnoreSettings" + }, + " extends ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.SerializableRecord", + "text": "SerializableRecord" + } + ], "path": "src/plugins/controls/common/types.ts", "deprecated": false, "trackAdoption": false, @@ -3290,7 +3233,7 @@ "label": "ControlLabelPosition", "description": [], "signature": [ - "\"twoLine\" | \"oneLine\"" + "\"oneLine\" | \"twoLine\"" ], "path": "src/plugins/controls/common/types.ts", "deprecated": false, @@ -3327,6 +3270,36 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "controls", + "id": "def-common.DEFAULT_AUTO_APPLY_SELECTIONS", + "type": "boolean", + "tags": [], + "label": "DEFAULT_AUTO_APPLY_SELECTIONS", + "description": [], + "signature": [ + "true" + ], + "path": "src/plugins/controls/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "controls", + "id": "def-common.DEFAULT_CONTROL_CHAINING", + "type": "CompoundType", + "tags": [], + "label": "DEFAULT_CONTROL_CHAINING", + "description": [], + "signature": [ + "\"NONE\" | \"HIERARCHICAL\"" + ], + "path": "src/plugins/controls/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "controls", "id": "def-common.DEFAULT_CONTROL_GROW", @@ -3347,7 +3320,7 @@ "label": "DEFAULT_CONTROL_LABEL_POSITION", "description": [], "signature": [ - "\"twoLine\" | \"oneLine\"" + "\"oneLine\" | \"twoLine\"" ], "path": "src/plugins/controls/common/constants.ts", "deprecated": false, @@ -3415,6 +3388,67 @@ "initialIsOpen": false } ], - "objects": [] + "objects": [ + { + "parentPluginId": "controls", + "id": "def-common.CONTROL_CHAINING_OPTIONS", + "type": "Object", + "tags": [], + "label": "CONTROL_CHAINING_OPTIONS", + "description": [], + "signature": [ + "{ readonly NONE: \"NONE\"; readonly HIERARCHICAL: \"HIERARCHICAL\"; }" + ], + "path": "src/plugins/controls/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "controls", + "id": "def-common.CONTROL_LABEL_POSITION_OPTIONS", + "type": "Object", + "tags": [], + "label": "CONTROL_LABEL_POSITION_OPTIONS", + "description": [], + "signature": [ + "{ readonly ONE_LINE: \"oneLine\"; readonly TWO_LINE: \"twoLine\"; }" + ], + "path": "src/plugins/controls/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "controls", + "id": "def-common.CONTROL_WIDTH_OPTIONS", + "type": "Object", + "tags": [], + "label": "CONTROL_WIDTH_OPTIONS", + "description": [], + "signature": [ + "{ readonly SMALL: \"small\"; readonly MEDIUM: \"medium\"; readonly LARGE: \"large\"; }" + ], + "path": "src/plugins/controls/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "controls", + "id": "def-common.DEFAULT_IGNORE_PARENT_SETTINGS", + "type": "Object", + "tags": [], + "label": "DEFAULT_IGNORE_PARENT_SETTINGS", + "description": [], + "signature": [ + "{ readonly ignoreFilters: false; readonly ignoreQuery: false; readonly ignoreTimerange: false; readonly ignoreValidations: false; }" + ], + "path": "src/plugins/controls/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ] } } \ No newline at end of file diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index f5dc85d777d4..eb98a295545b 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.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 | |-------------------|-----------|------------------------|-----------------| -| 135 | 0 | 131 | 14 | +| 135 | 0 | 131 | 15 | ## Client @@ -47,6 +47,9 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib ## Common +### Objects + + ### Interfaces diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index 179493c9fb58..bb64c3093d65 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.devdocs.json b/api_docs/dashboard.devdocs.json index 9d2107a8768c..d77e83955513 100644 --- a/api_docs/dashboard.devdocs.json +++ b/api_docs/dashboard.devdocs.json @@ -763,22 +763,7 @@ "label": "hits", "description": [], "signature": [ - { - "pluginId": "@kbn/content-management-utils", - "scope": "server", - "docId": "kibKbnContentManagementUtilsPluginApi", - "section": "def-server.SOWithMetadata", - "text": "SOWithMetadata" - }, - "<", - { - "pluginId": "dashboard", - "scope": "common", - "docId": "kibDashboardPluginApi", - "section": "def-common.DashboardAttributes", - "text": "DashboardAttributes" - }, - ">[]" + "Readonly<{ error?: Readonly<{ metadata?: Readonly<{} & {}> | undefined; } & { error: string; message: string; statusCode: number; }> | undefined; version?: string | undefined; namespaces?: string[] | undefined; createdBy?: string | undefined; updatedBy?: string | undefined; createdAt?: string | undefined; updatedAt?: string | undefined; managed?: boolean | undefined; originId?: string | undefined; } & { id: string; type: string; attributes: Readonly<{} & { title: string; description: string; timeRestore: boolean; }>; references: Readonly<{} & { id: string; type: string; name: string; }>[]; }>[]" ], "path": "src/plugins/dashboard/public/services/dashboard_content_management_service/lib/find_dashboards.ts", "deprecated": false, @@ -1300,15 +1285,7 @@ "section": "def-common.DashboardContainerInput", "text": "DashboardContainerInput" }, - ", \"executionContext\" | \"panels\" | \"controlGroupInput\">> & { dashboardId?: string | undefined; useHash?: boolean | undefined; preserveSavedFilters?: boolean | undefined; searchSessionId?: string | undefined; panels?: (", - { - "pluginId": "dashboard", - "scope": "common", - "docId": "kibDashboardPluginApi", - "section": "def-common.SavedDashboardPanel", - "text": "SavedDashboardPanel" - }, - " & ", + ", \"executionContext\" | \"panels\" | \"controlGroupInput\">> & { dashboardId?: string | undefined; useHash?: boolean | undefined; preserveSavedFilters?: boolean | undefined; searchSessionId?: string | undefined; panels?: (Omit | undefined; savedObjectId?: string | undefined; } & {}>; gridData: Readonly<{} & { i: string; y: number; w: number; h: number; x: number; }>; panelIndex: string; }>, \"panelConfig\"> & { panelConfig: Readonly<{ version?: string | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; enhancements?: Record | undefined; savedObjectId?: string | undefined; } & {}> & { [key: string]: any; }; } & ", { "pluginId": "@kbn/utility-types", "scope": "common", @@ -1530,7 +1507,111 @@ "functions": [], "interfaces": [], "enums": [], - "misc": [], + "misc": [ + { + "parentPluginId": "dashboard", + "id": "def-server.DashboardAttributes", + "type": "Type", + "tags": [], + "label": "DashboardAttributes", + "description": [], + "signature": [ + "Omit | undefined; timeFrom?: string | undefined; timeTo?: string | undefined; controlGroupInput?: Readonly<{ enhancements?: Record | undefined; } & { chainingSystem: ", + { + "pluginId": "controls", + "scope": "common", + "docId": "kibControlsPluginApi", + "section": "def-common.ControlGroupChainingSystem", + "text": "ControlGroupChainingSystem" + }, + "; labelPosition: ", + { + "pluginId": "controls", + "scope": "common", + "docId": "kibControlsPluginApi", + "section": "def-common.ControlLabelPosition", + "text": "ControlLabelPosition" + }, + "; autoApplySelections: boolean; ignoreParentSettings: Readonly<{} & { ignoreFilters: boolean; ignoreQuery: boolean; ignoreTimerange: boolean; ignoreValidations: boolean; }>; controls: Readonly<{ controlConfig?: Record | undefined; } & { id: string; type: string; order: number; grow: boolean; width: ", + { + "pluginId": "controls", + "scope": "common", + "docId": "kibControlsPluginApi", + "section": "def-common.ControlWidth", + "text": "ControlWidth" + }, + "; }>[]; }> | undefined; } & { options: Readonly<{} & { hidePanelTitles: boolean; syncTooltips: boolean; useMargins: boolean; syncColors: boolean; syncCursor: boolean; }>; title: string; description: string; kibanaSavedObjectMeta: Readonly<{ searchSource?: Readonly<{ type?: string | undefined; sort?: Record | Readonly<{ numeric_type?: \"date\" | \"date_nanos\" | \"long\" | \"double\" | undefined; } & { order: ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SortDirection", + "text": "SortDirection" + }, + "; }>>[] | undefined; filter?: Readonly<{ query?: Record | undefined; $state?: Readonly<{} & { store: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.FilterStateStore", + "text": "FilterStateStore" + }, + "; }> | undefined; } & { meta: Readonly<{ params?: any; key?: string | undefined; value?: string | undefined; type?: string | undefined; alias?: string | null | undefined; index?: string | undefined; disabled?: boolean | undefined; field?: string | undefined; group?: string | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; isMultiIndex?: boolean | undefined; } & {}>; }>[] | undefined; query?: Readonly<{} & { query: string | Record; language: string; }> | undefined; } & {}> | undefined; } & {}>; timeRestore: boolean; panels: Readonly<{ id?: string | undefined; version?: string | undefined; title?: string | undefined; panelRefName?: string | undefined; } & { type: string; panelConfig: Readonly<{ version?: string | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; enhancements?: Record | undefined; savedObjectId?: string | undefined; } & {}>; gridData: Readonly<{} & { i: string; y: number; w: number; h: number; x: number; }>; panelIndex: string; }>[]; }>, \"panels\"> & { panels: ", + "DashboardPanel", + "[]; }" + ], + "path": "src/plugins/dashboard/server/content_management/v3/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "dashboard", + "id": "def-server.DashboardAttributes", + "type": "Type", + "tags": [], + "label": "DashboardAttributes", + "description": [], + "signature": [ + "{ readonly version?: number | undefined; readonly timeRestore?: boolean | undefined; readonly refreshInterval?: Readonly<{ section?: number | undefined; display?: string | undefined; } & { value: number; pause: boolean; }> | undefined; readonly hits?: number | undefined; readonly timeFrom?: string | undefined; readonly timeTo?: string | undefined; readonly controlGroupInput?: Readonly<{ chainingSystem?: string | undefined; panelsJSON?: string | undefined; controlStyle?: string | undefined; ignoreParentSettingsJSON?: string | undefined; showApplySelections?: boolean | undefined; } & {}> | undefined; readonly optionsJSON?: string | undefined; readonly title: string; readonly description: string; readonly kibanaSavedObjectMeta: Readonly<{ searchSourceJSON?: string | undefined; } & {}>; readonly panelsJSON: string; }" + ], + "path": "src/plugins/dashboard/server/dashboard_saved_object/schema/v2/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "dashboard", + "id": "def-server.PUBLIC_API_PATH", + "type": "string", + "tags": [], + "label": "PUBLIC_API_PATH", + "description": [], + "signature": [ + "\"/api/dashboards/dashboard\"" + ], + "path": "src/plugins/dashboard/server/api/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], "objects": [], "setup": { "parentPluginId": "dashboard", @@ -1566,10 +1647,10 @@ "functions": [ { "parentPluginId": "dashboard", - "id": "def-common.convertPanelMapToSavedPanels", + "id": "def-common.convertPanelMapToPanelsArray", "type": "Function", "tags": [], - "label": "convertPanelMapToSavedPanels", + "label": "convertPanelMapToPanelsArray", "description": [], "signature": [ "(panels: ", @@ -1580,77 +1661,7 @@ "section": "def-common.DashboardPanelMap", "text": "DashboardPanelMap" }, - ", removeLegacyVersion?: boolean | undefined) => ", - { - "pluginId": "dashboard", - "scope": "common", - "docId": "kibDashboardPluginApi", - "section": "def-common.SavedDashboardPanel", - "text": "SavedDashboardPanel" - }, - "[]" - ], - "path": "src/plugins/dashboard/common/lib/dashboard_panel_converters.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "dashboard", - "id": "def-common.convertPanelMapToSavedPanels.$1", - "type": "Object", - "tags": [], - "label": "panels", - "description": [], - "signature": [ - { - "pluginId": "dashboard", - "scope": "common", - "docId": "kibDashboardPluginApi", - "section": "def-common.DashboardPanelMap", - "text": "DashboardPanelMap" - } - ], - "path": "src/plugins/dashboard/common/lib/dashboard_panel_converters.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "dashboard", - "id": "def-common.convertPanelMapToSavedPanels.$2", - "type": "CompoundType", - "tags": [], - "label": "removeLegacyVersion", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/dashboard/common/lib/dashboard_panel_converters.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "dashboard", - "id": "def-common.convertPanelStateToSavedDashboardPanel", - "type": "Function", - "tags": [], - "label": "convertPanelStateToSavedDashboardPanel", - "description": [], - "signature": [ - "(panelState: ", - { - "pluginId": "dashboard", - "scope": "common", - "docId": "kibDashboardPluginApi", - "section": "def-common.DashboardPanelState", - "text": "DashboardPanelState" - }, - "<", + ", removeLegacyVersion?: boolean | undefined) => { panelRefName?: string | undefined; id?: string | undefined; title?: string | undefined; type: string; gridData: Readonly<{} & { i: string; y: number; w: number; h: number; x: number; }>; panelIndex: string; panelConfig: _.Omit, removeLegacyVersion: boolean | undefined) => ", - { - "pluginId": "dashboard", - "scope": "common", - "docId": "kibDashboardPluginApi", - "section": "def-common.SavedDashboardPanel", - "text": "SavedDashboardPanel" - } + "> & { id: string; }, \"id\" | \"title\" | \"savedObjectId\">; version?: string | undefined; }[]" ], "path": "src/plugins/dashboard/common/lib/dashboard_panel_converters.ts", "deprecated": false, @@ -1673,28 +1677,19 @@ "children": [ { "parentPluginId": "dashboard", - "id": "def-common.convertPanelStateToSavedDashboardPanel.$1", + "id": "def-common.convertPanelMapToPanelsArray.$1", "type": "Object", "tags": [], - "label": "panelState", + "label": "panels", "description": [], "signature": [ { "pluginId": "dashboard", "scope": "common", "docId": "kibDashboardPluginApi", - "section": "def-common.DashboardPanelState", - "text": "DashboardPanelState" - }, - "<", - { - "pluginId": "embeddable", - "scope": "common", - "docId": "kibEmbeddablePluginApi", - "section": "def-common.SavedObjectEmbeddableInput", - "text": "SavedObjectEmbeddableInput" - }, - ">" + "section": "def-common.DashboardPanelMap", + "text": "DashboardPanelMap" + } ], "path": "src/plugins/dashboard/common/lib/dashboard_panel_converters.ts", "deprecated": false, @@ -1703,7 +1698,7 @@ }, { "parentPluginId": "dashboard", - "id": "def-common.convertPanelStateToSavedDashboardPanel.$2", + "id": "def-common.convertPanelMapToPanelsArray.$2", "type": "CompoundType", "tags": [], "label": "removeLegacyVersion", @@ -1722,75 +1717,14 @@ }, { "parentPluginId": "dashboard", - "id": "def-common.convertSavedDashboardPanelToPanelState", - "type": "Function", - "tags": [], - "label": "convertSavedDashboardPanelToPanelState", - "description": [], - "signature": [ - "(savedDashboardPanel: ", - { - "pluginId": "dashboard", - "scope": "common", - "docId": "kibDashboardPluginApi", - "section": "def-common.SavedDashboardPanel", - "text": "SavedDashboardPanel" - }, - ") => ", - { - "pluginId": "dashboard", - "scope": "common", - "docId": "kibDashboardPluginApi", - "section": "def-common.DashboardPanelState", - "text": "DashboardPanelState" - }, - "" - ], - "path": "src/plugins/dashboard/common/lib/dashboard_panel_converters.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "dashboard", - "id": "def-common.convertSavedDashboardPanelToPanelState.$1", - "type": "Object", - "tags": [], - "label": "savedDashboardPanel", - "description": [], - "signature": [ - { - "pluginId": "dashboard", - "scope": "common", - "docId": "kibDashboardPluginApi", - "section": "def-common.SavedDashboardPanel", - "text": "SavedDashboardPanel" - } - ], - "path": "src/plugins/dashboard/common/lib/dashboard_panel_converters.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, - { - "parentPluginId": "dashboard", - "id": "def-common.convertSavedPanelsToPanelMap", + "id": "def-common.convertPanelsArrayToPanelMap", "type": "Function", "tags": [], - "label": "convertSavedPanelsToPanelMap", + "label": "convertPanelsArrayToPanelMap", "description": [], "signature": [ "(panels?: ", - { - "pluginId": "dashboard", - "scope": "common", - "docId": "kibDashboardPluginApi", - "section": "def-common.SavedDashboardPanel", - "text": "SavedDashboardPanel" - }, + "DashboardPanel", "[] | undefined) => ", { "pluginId": "dashboard", @@ -1806,19 +1740,13 @@ "children": [ { "parentPluginId": "dashboard", - "id": "def-common.convertSavedPanelsToPanelMap.$1", + "id": "def-common.convertPanelsArrayToPanelMap.$1", "type": "Array", "tags": [], "label": "panels", "description": [], "signature": [ - { - "pluginId": "dashboard", - "scope": "common", - "docId": "kibDashboardPluginApi", - "section": "def-common.SavedDashboardPanel", - "text": "SavedDashboardPanel" - }, + "DashboardPanel", "[] | undefined" ], "path": "src/plugins/dashboard/common/lib/dashboard_panel_converters.ts", @@ -1982,7 +1910,13 @@ "({ attributes, references = [] }: ", "DashboardAttributesAndReferences", ", deps: ", - "InjectExtractDeps", + { + "pluginId": "dashboard", + "scope": "common", + "docId": "kibDashboardPluginApi", + "section": "def-common.InjectExtractDeps", + "text": "InjectExtractDeps" + }, ") => ", "DashboardAttributesAndReferences" ], @@ -2013,7 +1947,13 @@ "label": "deps", "description": [], "signature": [ - "InjectExtractDeps" + { + "pluginId": "dashboard", + "scope": "common", + "docId": "kibDashboardPluginApi", + "section": "def-common.InjectExtractDeps", + "text": "InjectExtractDeps" + } ], "path": "src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts", "deprecated": false, @@ -2035,13 +1975,19 @@ "({ attributes, references = [] }: ", "DashboardAttributesAndReferences", ", deps: ", - "InjectExtractDeps", - ") => ", { "pluginId": "dashboard", "scope": "common", "docId": "kibDashboardPluginApi", - "section": "def-common.DashboardAttributes", + "section": "def-common.InjectExtractDeps", + "text": "InjectExtractDeps" + }, + ") => ", + { + "pluginId": "dashboard", + "scope": "server", + "docId": "kibDashboardPluginApi", + "section": "def-server.DashboardAttributes", "text": "DashboardAttributes" } ], @@ -2072,7 +2018,13 @@ "label": "deps", "description": [], "signature": [ - "InjectExtractDeps" + { + "pluginId": "dashboard", + "scope": "common", + "docId": "kibDashboardPluginApi", + "section": "def-common.InjectExtractDeps", + "text": "InjectExtractDeps" + } ], "path": "src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts", "deprecated": false, @@ -2517,75 +2469,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "dashboard", - "id": "def-common.DashboardOptions", - "type": "Interface", - "tags": [], - "label": "DashboardOptions", - "description": [], - "path": "src/plugins/dashboard/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "dashboard", - "id": "def-common.DashboardOptions.hidePanelTitles", - "type": "boolean", - "tags": [], - "label": "hidePanelTitles", - "description": [], - "path": "src/plugins/dashboard/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "dashboard", - "id": "def-common.DashboardOptions.useMargins", - "type": "boolean", - "tags": [], - "label": "useMargins", - "description": [], - "path": "src/plugins/dashboard/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "dashboard", - "id": "def-common.DashboardOptions.syncColors", - "type": "boolean", - "tags": [], - "label": "syncColors", - "description": [], - "path": "src/plugins/dashboard/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "dashboard", - "id": "def-common.DashboardOptions.syncTooltips", - "type": "boolean", - "tags": [], - "label": "syncTooltips", - "description": [], - "path": "src/plugins/dashboard/common/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "dashboard", - "id": "def-common.DashboardOptions.syncCursor", - "type": "boolean", - "tags": [], - "label": "syncCursor", - "description": [], - "path": "src/plugins/dashboard/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "dashboard", "id": "def-common.DashboardPanelMap", @@ -2667,7 +2550,7 @@ "label": "gridData", "description": [], "signature": [ - "GridData" + "{ readonly i: string; readonly y: number; readonly w: number; readonly h: number; readonly x: number; }" ], "path": "src/plugins/dashboard/common/dashboard_container/types.ts", "deprecated": false, @@ -2731,130 +2614,41 @@ }, { "parentPluginId": "dashboard", - "id": "def-common.SavedDashboardPanel", + "id": "def-common.InjectExtractDeps", "type": "Interface", "tags": [], - "label": "SavedDashboardPanel", - "description": [ - "\nA saved dashboard panel parsed directly from the Dashboard Attributes panels JSON" - ], - "path": "src/plugins/dashboard/common/content_management/v1/types.ts", + "label": "InjectExtractDeps", + "description": [], + "path": "src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "dashboard", - "id": "def-common.SavedDashboardPanel.embeddableConfig", + "id": "def-common.InjectExtractDeps.embeddablePersistableStateService", "type": "Object", "tags": [], - "label": "embeddableConfig", + "label": "embeddablePersistableStateService", "description": [], "signature": [ - "{ [key: string]: ", { - "pluginId": "@kbn/utility-types", + "pluginId": "kibanaUtils", "scope": "common", - "docId": "kibKbnUtilityTypesPluginApi", - "section": "def-common.Serializable", - "text": "Serializable" + "docId": "kibKibanaUtilsPluginApi", + "section": "def-common.PersistableStateService", + "text": "PersistableStateService" }, - "; }" - ], - "path": "src/plugins/dashboard/common/content_management/v1/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "dashboard", - "id": "def-common.SavedDashboardPanel.id", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/dashboard/common/content_management/v1/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "dashboard", - "id": "def-common.SavedDashboardPanel.type", - "type": "string", - "tags": [], - "label": "type", - "description": [], - "path": "src/plugins/dashboard/common/content_management/v1/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "dashboard", - "id": "def-common.SavedDashboardPanel.panelRefName", - "type": "string", - "tags": [], - "label": "panelRefName", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/dashboard/common/content_management/v1/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "dashboard", - "id": "def-common.SavedDashboardPanel.gridData", - "type": "Object", - "tags": [], - "label": "gridData", - "description": [], - "signature": [ - "GridData" - ], - "path": "src/plugins/dashboard/common/content_management/v1/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "dashboard", - "id": "def-common.SavedDashboardPanel.panelIndex", - "type": "string", - "tags": [], - "label": "panelIndex", - "description": [], - "path": "src/plugins/dashboard/common/content_management/v1/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "dashboard", - "id": "def-common.SavedDashboardPanel.title", - "type": "string", - "tags": [], - "label": "title", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/dashboard/common/content_management/v1/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "dashboard", - "id": "def-common.SavedDashboardPanel.version", - "type": "string", - "tags": [], - "label": "version", - "description": [ - "\nThis version key was used to store Kibana version information from versions 7.3.0 -> 8.11.0.\nAs of version 8.11.0, the versioning information is now per-embeddable-type and is stored on the\nembeddable's input. (embeddableConfig in this type)." - ], - "signature": [ - "string | undefined" + "<", + { + "pluginId": "embeddable", + "scope": "common", + "docId": "kibEmbeddablePluginApi", + "section": "def-common.EmbeddableStateWithType", + "text": "EmbeddableStateWithType" + }, + ">" ], - "path": "src/plugins/dashboard/common/content_management/v1/types.ts", + "path": "src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts", "deprecated": false, "trackAdoption": false } @@ -2864,29 +2658,6 @@ ], "enums": [], "misc": [ - { - "parentPluginId": "dashboard", - "id": "def-common.DashboardAttributes", - "type": "Type", - "tags": [], - "label": "DashboardAttributes", - "description": [], - "signature": [ - "Omit<", - { - "pluginId": "dashboard", - "scope": "common", - "docId": "kibDashboardPluginApi", - "section": "def-common.DashboardAttributes", - "text": "DashboardAttributes" - }, - ", \"controlGroupInput\"> & { controlGroupInput?: ControlGroupAttributesV2 | undefined; }" - ], - "path": "src/plugins/dashboard/common/content_management/v2/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "dashboard", "id": "def-common.DashboardContainerByReferenceInput", @@ -2975,13 +2746,7 @@ "text": "SerializableRecord" }, " | undefined; disabledActions?: string[] | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; panels?: ", - { - "pluginId": "dashboard", - "scope": "common", - "docId": "kibDashboardPluginApi", - "section": "def-common.SavedDashboardPanel", - "text": "SavedDashboardPanel" - }, + "DashboardPanel", "[] | undefined; }" ], "path": "src/plugins/dashboard/common/types.ts", diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index e0a4caa1b1e8..d16af22e2b35 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] --- import dashboardObj from './dashboard.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 | |-------------------|-----------|------------------------|-----------------| -| 130 | 0 | 125 | 14 | +| 114 | 0 | 111 | 13 | ## Client @@ -51,6 +51,9 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib ### Start +### Consts, variables and types + + ## Common ### Objects diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index 16db1515083a..d751d31185d1 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-06 +date: 2024-11-12 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 694155fd543f..0951e09a7e45 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-06 +date: 2024-11-12 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 be8bef73ffa2..0d5b37eda3c0 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-06 +date: 2024-11-12 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 c762301147ad..a524ed87dd39 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.devdocs.json b/api_docs/data_search.devdocs.json index 48f76de6586b..53f23d269906 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -15780,7 +15780,15 @@ "section": "def-common.IKibanaSearchResponse", "text": "IKibanaSearchResponse" }, - " | undefined) => boolean" + " | { response: ", + { + "pluginId": "@kbn/search-types", + "scope": "common", + "docId": "kibKbnSearchTypesPluginApi", + "section": "def-common.IKibanaSearchResponse", + "text": "IKibanaSearchResponse" + }, + "; } | undefined) => boolean" ], "path": "src/plugins/data/common/search/utils.ts", "deprecated": false, @@ -15789,7 +15797,7 @@ { "parentPluginId": "data", "id": "def-common.isAbortResponse.$1", - "type": "Object", + "type": "CompoundType", "tags": [], "label": "response", "description": [], @@ -15801,7 +15809,15 @@ "section": "def-common.IKibanaSearchResponse", "text": "IKibanaSearchResponse" }, - " | undefined" + " | { response: ", + { + "pluginId": "@kbn/search-types", + "scope": "common", + "docId": "kibKbnSearchTypesPluginApi", + "section": "def-common.IKibanaSearchResponse", + "text": "IKibanaSearchResponse" + }, + "; } | undefined" ], "path": "src/plugins/data/common/search/utils.ts", "deprecated": false, diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 1b615574c102..4801aeb14687 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-06 +date: 2024-11-12 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 025d5a49c4b2..ca09f822938c 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-06 +date: 2024-11-12 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 0ac756ae0ebd..287eeb2826c4 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-06 +date: 2024-11-12 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 24a2ffdbf8ab..97d8efb2e4f7 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-06 +date: 2024-11-12 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 7fa82008f298..d9bfe3d16257 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-06 +date: 2024-11-12 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 d7eda0937f39..e06438b19b31 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-06 +date: 2024-11-12 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 ea86b04d3c6d..92e6d765b771 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-06 +date: 2024-11-12 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 b0a5233462ae..0f42873f1c07 100644 --- a/api_docs/dataset_quality.devdocs.json +++ b/api_docs/dataset_quality.devdocs.json @@ -457,7 +457,7 @@ "DatasetQualityRouteHandlerResources", ", { aggregatable: boolean; datasets: string[]; }, ", "DatasetQualityRouteCreateOptions", - ">; \"GET /internal/dataset_quality/data_streams/degraded_docs\": ", + ">; \"GET /internal/dataset_quality/data_streams/total_docs\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -465,7 +465,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"GET /internal/dataset_quality/data_streams/degraded_docs\", ", + "<\"GET /internal/dataset_quality/data_streams/total_docs\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -479,13 +479,39 @@ "TypeC", "<{ type: ", "KeyofC", - "<{ logs: null; metrics: null; traces: null; synthetics: null; profiling: null; }>; }>, ", + "<{ logs: null; metrics: null; traces: null; synthetics: null; profiling: null; }>; }>]>; }>, ", + "DatasetQualityRouteHandlerResources", + ", { totalDocs: { dataset: string; count: number; }[]; }, ", + "DatasetQualityRouteCreateOptions", + ">; \"GET /internal/dataset_quality/data_streams/degraded_docs\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/dataset_quality/data_streams/degraded_docs\", ", + "TypeC", + "<{ query: ", + "IntersectionC", + "<[", + "TypeC", + "<{ start: ", + "Type", + "; end: ", + "Type", + "; }>, ", + "TypeC", + "<{ types: ", + "Type", + "<(\"profiling\" | \"metrics\" | \"synthetics\" | \"traces\" | \"logs\")[], (\"profiling\" | \"metrics\" | \"synthetics\" | \"traces\" | \"logs\")[], unknown>; }>, ", "PartialC", "<{ datasetQuery: ", "StringC", "; }>]>; }>, ", "DatasetQualityRouteHandlerResources", - ", { degradedDocs: { dataset: string; count: number; docsCount: number; percentage: number; }[]; }, ", + ", { degradedDocs: { dataset: string; count: number; }[]; }, ", "DatasetQualityRouteCreateOptions", ">; \"GET /internal/dataset_quality/data_streams/stats\": ", { @@ -798,7 +824,7 @@ "DatasetQualityRouteHandlerResources", ", { aggregatable: boolean; datasets: string[]; }, ", "DatasetQualityRouteCreateOptions", - ">; \"GET /internal/dataset_quality/data_streams/degraded_docs\": ", + ">; \"GET /internal/dataset_quality/data_streams/total_docs\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -806,7 +832,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"GET /internal/dataset_quality/data_streams/degraded_docs\", ", + "<\"GET /internal/dataset_quality/data_streams/total_docs\", ", "TypeC", "<{ query: ", "IntersectionC", @@ -820,13 +846,39 @@ "TypeC", "<{ type: ", "KeyofC", - "<{ logs: null; metrics: null; traces: null; synthetics: null; profiling: null; }>; }>, ", + "<{ logs: null; metrics: null; traces: null; synthetics: null; profiling: null; }>; }>]>; }>, ", + "DatasetQualityRouteHandlerResources", + ", { totalDocs: { dataset: string; count: number; }[]; }, ", + "DatasetQualityRouteCreateOptions", + ">; \"GET /internal/dataset_quality/data_streams/degraded_docs\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/dataset_quality/data_streams/degraded_docs\", ", + "TypeC", + "<{ query: ", + "IntersectionC", + "<[", + "TypeC", + "<{ start: ", + "Type", + "; end: ", + "Type", + "; }>, ", + "TypeC", + "<{ types: ", + "Type", + "<(\"profiling\" | \"metrics\" | \"synthetics\" | \"traces\" | \"logs\")[], (\"profiling\" | \"metrics\" | \"synthetics\" | \"traces\" | \"logs\")[], unknown>; }>, ", "PartialC", "<{ datasetQuery: ", "StringC", "; }>]>; }>, ", "DatasetQualityRouteHandlerResources", - ", { degradedDocs: { dataset: string; count: number; docsCount: number; percentage: number; }[]; }, ", + ", { degradedDocs: { dataset: string; count: number; }[]; }, ", "DatasetQualityRouteCreateOptions", ">; \"GET /internal/dataset_quality/data_streams/stats\": ", { diff --git a/api_docs/dataset_quality.mdx b/api_docs/dataset_quality.mdx index 76ecb3ab0e19..781077b90fbd 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-06 +date: 2024-11-12 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 eb8ebbe13fc0..b8625def2dbb 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -22,7 +22,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | actions, savedObjectsTagging, ml, enterpriseSearch | - | | | @kbn/core-saved-objects-browser-internal, @kbn/core, savedObjects, visualizations, aiops, dataVisualizer, ml, dashboardEnhanced, graph, lens, securitySolution, eventAnnotation, @kbn/core-saved-objects-browser-mocks | - | | | @kbn/core, embeddable, savedObjects, visualizations, canvas, graph, ml | - | -| | @kbn/core-saved-objects-base-server-internal, @kbn/core-saved-objects-migration-server-internal, @kbn/core-saved-objects-server-internal, @kbn/core-ui-settings-server-internal, @kbn/core-usage-data-server-internal, taskManager, dataViews, spaces, actions, share, data, alerting, @kbn/core-saved-objects-migration-server-mocks, lens, cases, savedSearch, canvas, fleet, cloudSecurityPosture, ml, logsShared, graph, lists, maps, visualizations, infra, apmDataAccess, securitySolution, apm, slo, synthetics, uptime, dashboard, eventAnnotation, links, savedObjectsManagement, @kbn/core-test-helpers-so-type-serializer, @kbn/core-saved-objects-api-server-internal | - | +| | @kbn/core-saved-objects-base-server-internal, @kbn/core-saved-objects-migration-server-internal, @kbn/core-saved-objects-server-internal, @kbn/core-ui-settings-server-internal, @kbn/core-usage-data-server-internal, taskManager, dataViews, spaces, share, actions, data, alerting, dashboard, @kbn/core-saved-objects-migration-server-mocks, lens, cases, savedSearch, canvas, fleet, cloudSecurityPosture, ml, logsShared, graph, lists, maps, infra, visualizations, apmDataAccess, securitySolution, apm, slo, synthetics, uptime, eventAnnotation, links, savedObjectsManagement, @kbn/core-test-helpers-so-type-serializer, @kbn/core-saved-objects-api-server-internal | - | | | stackAlerts, alerting, securitySolution, inputControlVis | - | | | graph, stackAlerts, inputControlVis, securitySolution | - | | | dataVisualizer, stackAlerts, expressionPartitionVis | - | @@ -49,7 +49,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-browser-mocks, fleet, graph, lists, osquery, securitySolution, alerting | - | | | @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, savedObjects, 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, lens, cases, savedSearch, canvas, savedObjectsTagging, graph, lists, maps, visualizations, securitySolution, dashboard, @kbn/core-test-helpers-so-type-serializer | - | +| | @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 | - | @@ -67,10 +67,10 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | securitySolution | - | | | @kbn/monaco, securitySolution | - | | | cloudSecurityPosture, securitySolution | - | -| | alerting, observabilityAIAssistant, fleet, cloudSecurityPosture, entityManager, serverlessSearch, transform, upgradeAssistant, apm, synthetics, security | - | +| | alerting, observabilityAIAssistant, fleet, cloudSecurityPosture, entityManager, apm, serverlessSearch, transform, upgradeAssistant, synthetics, security | - | | | actions, alerting | - | | | monitoring | - | -| | @kbn/core-saved-objects-api-browser, @kbn/core, savedObjectsManagement, savedObjects, visualizations, savedObjectsTagging, eventAnnotation, lens, maps, graph, dashboard, kibanaUtils, expressions, data, savedObjectsTaggingOss, embeddable, uiActionsEnhanced, canvas, dashboardEnhanced, globalSearchProviders, controls | - | +| | @kbn/core-saved-objects-api-browser, @kbn/core, savedObjectsManagement, savedObjects, visualizations, savedObjectsTagging, eventAnnotation, lens, maps, graph, dashboard, kibanaUtils, expressions, data, savedObjectsTaggingOss, embeddable, uiActionsEnhanced, controls, canvas, dashboardEnhanced, globalSearchProviders | - | | | @kbn/core-saved-objects-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, home, savedObjects, visualizations, lens, visTypeTimeseries, @kbn/core-saved-objects-browser-mocks | - | | | @kbn/core-saved-objects-browser-internal, savedObjects, @kbn/core-saved-objects-browser-mocks | - | | | home, @kbn/core-saved-objects-browser-mocks, @kbn/core-saved-objects-browser-internal | - | @@ -102,7 +102,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-saved-objects-api-server-internal | - | | | @kbn/core-saved-objects-api-server-internal | - | | | @kbn/core-saved-objects-api-server-internal, canvas | - | -| | @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-migration-server-internal, spaces, data, savedSearch, cloudSecurityPosture, visualizations, dashboard, @kbn/core-test-helpers-so-type-serializer | - | +| | @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-migration-server-internal, spaces, data, dashboard, savedSearch, cloudSecurityPosture, visualizations, @kbn/core-test-helpers-so-type-serializer | - | | | @kbn/core-root-browser-internal, @kbn/core-saved-objects-browser-mocks | - | | | fleet, exploratoryView, osquery, synthetics | - | | | @kbn/security-plugin-types-server, telemetry, fleet, profiling, @kbn/security-authorization-core, security | - | @@ -158,6 +158,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | security | - | | | observabilityShared | - | | | @kbn/react-kibana-context-styled, kibanaReact | - | +| | indexLifecycleManagement | - | | | @kbn/reporting-public, discover | - | | | discover, @kbn/management-settings-field-definition | - | | | @kbn/content-management-table-list-view, filesManagement | - | @@ -169,13 +170,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | encryptedSavedObjects | - | | | @kbn/esql-validation-autocomplete | - | | | @kbn/monaco | - | -| | reporting | - | -| | @kbn/reporting-export-types-csv, reporting | - | -| | @kbn/reporting-export-types-csv, reporting | - | | | reporting | - | | | reporting | - | | | @kbn/reporting-export-types-pdf | - | -| | @kbn/reporting-csv-share-panel | - | | | security, aiops, licenseManagement, ml, crossClusterReplication, logstash, painlessLab, searchprofiler, watcher, profiling, apm, 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 | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index bda4c89ae780..efc3f2961fa6 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -402,23 +402,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] -## @kbn/reporting-csv-share-panel - -| Deprecated API | Reference location(s) | Remove By | -| ---------------|-----------|-----------| -| | [get_csv_panel_action.tsx](https://github.com/elastic/kibana/tree/main/packages/kbn-reporting/get_csv_panel_actions/panel_actions/get_csv_panel_action.tsx#:~:text=createImmediateReport), [get_csv_panel_action.test.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-reporting/get_csv_panel_actions/panel_actions/get_csv_panel_action.test.ts#:~:text=createImmediateReport) | - | - - - -## @kbn/reporting-export-types-csv - -| Deprecated API | Reference location(s) | Remove By | -| ---------------|-----------|-----------| -| | [csv_searchsource_immediate.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts#:~:text=JobParamsDownloadCSV), [csv_searchsource_immediate.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts#:~:text=JobParamsDownloadCSV), [csv_searchsource_immediate.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts#:~:text=JobParamsDownloadCSV), [csv_searchsource_immediate.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts#:~:text=JobParamsDownloadCSV) | - | -| | [csv_searchsource_immediate.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts#:~:text=CSV_SEARCHSOURCE_IMMEDIATE_TYPE), [csv_searchsource_immediate.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts#:~:text=CSV_SEARCHSOURCE_IMMEDIATE_TYPE), [csv_searchsource_immediate.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts#:~:text=CSV_SEARCHSOURCE_IMMEDIATE_TYPE), [csv_searchsource_immediate.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts#:~:text=CSV_SEARCHSOURCE_IMMEDIATE_TYPE) | - | - - - ## @kbn/reporting-export-types-pdf | Deprecated API | Reference location(s) | Remove By | @@ -961,6 +944,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| | | [license.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/index_lifecycle_management/server/services/license.ts#:~:text=license%24) | 8.8.0 | +| | [mocks.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/index_lifecycle_management/__jest__/mocks.ts#:~:text=max_size), [deserializer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts#:~:text=max_size), [deserializer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts#:~:text=max_size), [deserializer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts#:~:text=max_size), [serializer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts#:~:text=max_size), [serializer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts#:~:text=max_size), [serializer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts#:~:text=max_size), [serializer.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts#:~:text=max_size), [rollover.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_list/policy_flyout/components/rollover.tsx#:~:text=max_size), [rollover.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/index_lifecycle_management/public/application/sections/policy_list/policy_flyout/components/rollover.tsx#:~:text=max_size)+ 7 more | - | @@ -1219,9 +1203,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [core.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/reporting/server/core.ts#:~:text=CsvSearchSourceImmediateExportType), [core.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/reporting/server/core.ts#:~:text=CsvSearchSourceImmediateExportType) | - | -| | [csv_searchsource_immediate.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/reporting/server/routes/internal/generate/csv_searchsource_immediate.ts#:~:text=JobParamsDownloadCSV), [csv_searchsource_immediate.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/reporting/server/routes/internal/generate/csv_searchsource_immediate.ts#:~:text=JobParamsDownloadCSV) | - | -| | [csv_searchsource_immediate.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/reporting/server/routes/internal/generate/csv_searchsource_immediate.ts#:~:text=CSV_SEARCHSOURCE_IMMEDIATE_TYPE), [csv_searchsource_immediate.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/reporting/server/routes/internal/generate/csv_searchsource_immediate.ts#:~:text=CSV_SEARCHSOURCE_IMMEDIATE_TYPE), [csv_searchsource_immediate.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/reporting/server/routes/internal/generate/csv_searchsource_immediate.ts#:~:text=CSV_SEARCHSOURCE_IMMEDIATE_TYPE) | - | | | [get_document_payload.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/reporting/server/routes/common/jobs/get_document_payload.ts#:~:text=CSV_JOB_TYPE_DEPRECATED), [get_document_payload.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/reporting/server/routes/common/jobs/get_document_payload.ts#:~:text=CSV_JOB_TYPE_DEPRECATED) | - | | | [core.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/reporting/server/core.ts#:~:text=PdfV1ExportType), [core.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/reporting/server/core.ts#:~:text=PdfV1ExportType) | - | @@ -1376,7 +1357,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx#:~:text=DeprecatedCellValueElementProps), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx#:~:text=DeprecatedCellValueElementProps) | - | | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx#:~:text=DeprecatedRowRenderer), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx#:~:text=DeprecatedRowRenderer) | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=BeatFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=BeatFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=BeatFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=BeatFields) | - | -| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields)+ 72 more | - | +| | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/types/header_actions/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kuery/index.ts#:~:text=BrowserFields)+ 70 more | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=IndexFieldsStrategyRequest), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyRequest), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyRequest), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyRequest), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=IndexFieldsStrategyRequest), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=IndexFieldsStrategyRequest) | - | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/search_strategy/index_fields/index.ts#:~:text=IndexFieldsStrategyResponse), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyResponse), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyResponse), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/search_strategy/endpoint_fields/index.ts#:~:text=IndexFieldsStrategyResponse), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=IndexFieldsStrategyResponse), [middleware.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts#:~:text=IndexFieldsStrategyResponse) | - | | | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/types.ts#:~:text=SimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/types.ts#:~:text=SimpleSavedObject) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 29b66afafbf7..5c53f577e6b0 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index ffc1501149a8..4b27de358490 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index 9f536018730f..e160bb054f6e 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index 3d3bf711922b..29651f5536a5 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/discover_shared.mdx b/api_docs/discover_shared.mdx index f69d2a37c207..e739cfef4d20 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverShared'] --- import discoverSharedObj from './discover_shared.devdocs.json'; diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index cccc4dc30a3f..a5890f386a49 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/elastic_assistant.devdocs.json b/api_docs/elastic_assistant.devdocs.json index 4df33db88b4d..3fe39450a7c8 100644 --- a/api_docs/elastic_assistant.devdocs.json +++ b/api_docs/elastic_assistant.devdocs.json @@ -1683,6 +1683,27 @@ "path": "x-pack/plugins/elastic_assistant/server/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "elasticAssistant", + "id": "def-server.AssistantToolParams.telemetry", + "type": "Object", + "tags": [], + "label": "telemetry", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-analytics-server", + "scope": "server", + "docId": "kibKbnCoreAnalyticsServerPluginApi", + "section": "def-server.AnalyticsServiceSetup", + "text": "AnalyticsServiceSetup" + }, + " | undefined" + ], + "path": "x-pack/plugins/elastic_assistant/server/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index b2d74ee427ef..d15d05811d12 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './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 | |-------------------|-----------|------------------------|-----------------| -| 52 | 0 | 37 | 2 | +| 53 | 0 | 38 | 2 | ## Server diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 72852e92db3e..99fe95318c4d 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-06 +date: 2024-11-12 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 6cac4c9edcbc..38e3f8964dbf 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-06 +date: 2024-11-12 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 936301e9f136..01184c77221c 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-06 +date: 2024-11-12 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 a01e6b4bf365..6e845c5eacbc 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-06 +date: 2024-11-12 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 128358a3c149..3aa1ca62de52 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entitiesDataAccess'] --- import entitiesDataAccessObj from './entities_data_access.devdocs.json'; diff --git a/api_docs/entity_manager.mdx b/api_docs/entity_manager.mdx index 5eca7049e93c..6eed6037e559 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entityManager'] --- import entityManagerObj from './entity_manager.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index a304bee597e8..dcbbd723d478 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-06 +date: 2024-11-12 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 0151e029a935..9ba78a757613 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-06 +date: 2024-11-12 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 4630c504aa9d..4127d6baa15d 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-06 +date: 2024-11-12 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 cc36c1a89c9b..4b25969e7239 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-06 +date: 2024-11-12 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 21a8b747911c..253efc5daaec 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-06 +date: 2024-11-12 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 d6d56dddacb8..3e9e78585d71 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-06 +date: 2024-11-12 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 b0bb6c22bfd2..6a8a5f76c162 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-06 +date: 2024-11-12 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 7831c3a04fd7..eebaeb3c69fc 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-06 +date: 2024-11-12 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 676873f51068..fc1020122f57 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-06 +date: 2024-11-12 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 e0496b040bbe..91104c370d99 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-06 +date: 2024-11-12 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 7a872c8b46d7..ed1c4f3b3682 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-06 +date: 2024-11-12 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 9a5d33f750d2..f020c2fbac32 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-06 +date: 2024-11-12 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 47830f994028..7b41cedd0de5 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-06 +date: 2024-11-12 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 bda279797d76..e26c63b99c97 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-06 +date: 2024-11-12 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 91487dfd4e3e..c9b73f9a57e9 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-06 +date: 2024-11-12 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 30ed4f45da2d..c77344c8f7da 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-06 +date: 2024-11-12 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 52993a1109d9..5a6f58e76de9 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-06 +date: 2024-11-12 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 d510a9d43d2e..f4e196a5756b 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-06 +date: 2024-11-12 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 fe32526b4b9b..379cad7b3b68 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-06 +date: 2024-11-12 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 fa30eb121c0e..e98d44b5029a 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-06 +date: 2024-11-12 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 428aca2034b2..955e3bd1bb77 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-06 +date: 2024-11-12 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 eb1affd111c8..0411c023a941 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-06 +date: 2024-11-12 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 43cd3aa87155..2152f8c9eb64 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-06 +date: 2024-11-12 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 ede8ade212ff..182306396fd2 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-06 +date: 2024-11-12 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 e53791567188..2ac8c1ad62ae 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-06 +date: 2024-11-12 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 edf46fa95755..25d75fea904e 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-06 +date: 2024-11-12 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 eee2ea3b7266..e7259ba5ea61 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-06 +date: 2024-11-12 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 1b09c8410d59..95969d738570 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -990,27 +990,6 @@ "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "fleet", - "id": "def-public.GetPackagesResponse.response", - "type": "Array", - "tags": [], - "label": "response", - "description": [], - "signature": [ - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.PackageList", - "text": "PackageList" - }, - " | undefined" - ], - "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", - "deprecated": false, - "trackAdoption": false } ], "initialIsOpen": false @@ -4206,6 +4185,17 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "fleet", + "id": "def-public.EPM_API_ROUTES.INFO_WITHOUT_VERSION_PATTERN", + "type": "string", + "tags": [], + "label": "INFO_WITHOUT_VERSION_PATTERN", + "description": [], + "path": "x-pack/plugins/fleet/common/constants/routes.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "fleet", "id": "def-public.EPM_API_ROUTES.INFO_PATTERN", @@ -4360,39 +4350,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "fleet", - "id": "def-public.EPM_API_ROUTES.INFO_PATTERN_DEPRECATED", - "type": "string", - "tags": [], - "label": "INFO_PATTERN_DEPRECATED", - "description": [], - "path": "x-pack/plugins/fleet/common/constants/routes.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "fleet", - "id": "def-public.EPM_API_ROUTES.INSTALL_FROM_REGISTRY_PATTERN_DEPRECATED", - "type": "string", - "tags": [], - "label": "INSTALL_FROM_REGISTRY_PATTERN_DEPRECATED", - "description": [], - "path": "x-pack/plugins/fleet/common/constants/routes.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "fleet", - "id": "def-public.EPM_API_ROUTES.DELETE_PATTERN_DEPRECATED", - "type": "string", - "tags": [], - "label": "DELETE_PATTERN_DEPRECATED", - "description": [], - "path": "x-pack/plugins/fleet/common/constants/routes.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "fleet", "id": "def-public.EPM_API_ROUTES.REAUTHORIZE_TRANSFORMS", @@ -20932,36 +20889,6 @@ "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.BulkInstallPackagesResponse.response", - "type": "Array", - "tags": [], - "label": "response", - "description": [], - "signature": [ - "(", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.BulkInstallPackageInfo", - "text": "BulkInstallPackageInfo" - }, - " | ", - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.IBulkInstallPackageHTTPError", - "text": "IBulkInstallPackageHTTPError" - }, - ")[] | undefined" - ], - "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", - "deprecated": false, - "trackAdoption": false } ], "initialIsOpen": false @@ -22978,27 +22905,6 @@ "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.GetInfoResponse.response", - "type": "CompoundType", - "tags": [], - "label": "response", - "description": [], - "signature": [ - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.PackageInfo", - "text": "PackageInfo" - }, - " | undefined" - ], - "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", - "deprecated": false, - "trackAdoption": false } ], "initialIsOpen": false @@ -23170,27 +23076,6 @@ "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.GetPackagesResponse.response", - "type": "Array", - "tags": [], - "label": "response", - "description": [], - "signature": [ - { - "pluginId": "fleet", - "scope": "common", - "docId": "kibFleetPluginApi", - "section": "def-common.PackageList", - "text": "PackageList" - }, - " | undefined" - ], - "path": "x-pack/plugins/fleet/common/types/rest_spec/epm.ts", - "deprecated": false, - "trackAdoption": false } ], "initialIsOpen": false @@ -28470,10 +28355,10 @@ "section": "def-common.RegistrySearchResult", "text": "RegistrySearchResult" }, - "> & { id: string; integration?: string | undefined; installationInfo?: ", - "InstallationInfo", - " | undefined; savedObject?: ", + "> & { id: string; integration?: string | undefined; savedObject?: ", "InstallableSavedObject", + " | undefined; installationInfo?: ", + "InstallationInfo", " | undefined; }" ], "path": "x-pack/plugins/fleet/common/types/models/epm.ts", @@ -30509,6 +30394,17 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "fleet", + "id": "def-common.EPM_API_ROUTES.INFO_WITHOUT_VERSION_PATTERN", + "type": "string", + "tags": [], + "label": "INFO_WITHOUT_VERSION_PATTERN", + "description": [], + "path": "x-pack/plugins/fleet/common/constants/routes.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "fleet", "id": "def-common.EPM_API_ROUTES.INFO_PATTERN", @@ -30663,39 +30559,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "fleet", - "id": "def-common.EPM_API_ROUTES.INFO_PATTERN_DEPRECATED", - "type": "string", - "tags": [], - "label": "INFO_PATTERN_DEPRECATED", - "description": [], - "path": "x-pack/plugins/fleet/common/constants/routes.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.EPM_API_ROUTES.INSTALL_FROM_REGISTRY_PATTERN_DEPRECATED", - "type": "string", - "tags": [], - "label": "INSTALL_FROM_REGISTRY_PATTERN_DEPRECATED", - "description": [], - "path": "x-pack/plugins/fleet/common/constants/routes.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "fleet", - "id": "def-common.EPM_API_ROUTES.DELETE_PATTERN_DEPRECATED", - "type": "string", - "tags": [], - "label": "DELETE_PATTERN_DEPRECATED", - "description": [], - "path": "x-pack/plugins/fleet/common/constants/routes.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "fleet", "id": "def-common.EPM_API_ROUTES.REAUTHORIZE_TRANSFORMS", @@ -30904,7 +30767,7 @@ "label": "getInstallPath", "description": [], "signature": [ - "(pkgName: string, pkgVersion: string) => string" + "(pkgName: string, pkgVersion?: string | undefined) => string" ], "path": "x-pack/plugins/fleet/common/services/routes.ts", "deprecated": false, @@ -30933,12 +30796,12 @@ "label": "pkgVersion", "description": [], "signature": [ - "string" + "string | undefined" ], "path": "x-pack/plugins/fleet/common/services/routes.ts", "deprecated": false, "trackAdoption": false, - "isRequired": true + "isRequired": false } ], "returnComment": [] @@ -30967,7 +30830,7 @@ "label": "getRemovePath", "description": [], "signature": [ - "(pkgName: string, pkgVersion: string) => string" + "(pkgName: string, pkgVersion?: string | undefined) => string" ], "path": "x-pack/plugins/fleet/common/services/routes.ts", "deprecated": false, @@ -30996,12 +30859,12 @@ "label": "pkgVersion", "description": [], "signature": [ - "string" + "string | undefined" ], "path": "x-pack/plugins/fleet/common/services/routes.ts", "deprecated": false, "trackAdoption": false, - "isRequired": true + "isRequired": false } ], "returnComment": [] diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 0bd611aad070..f9f9b010bdb5 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-06 +date: 2024-11-12 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 | |-------------------|-----------|------------------------|-----------------| -| 1426 | 5 | 1303 | 81 | +| 1418 | 5 | 1295 | 81 | ## Client diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 2c1de2526413..bd4663eb054b 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-06 +date: 2024-11-12 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 bc911bac8a45..e0a6f3f5dedd 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 3eb519f22181..1750cc9c4839 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-06 +date: 2024-11-12 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 dbdd6475436d..b27ee510657c 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'imageEmbeddable'] --- import imageEmbeddableObj from './image_embeddable.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.devdocs.json b/api_docs/index_lifecycle_management.devdocs.json index 03825ec75860..d7ec7a91677c 100644 --- a/api_docs/index_lifecycle_management.devdocs.json +++ b/api_docs/index_lifecycle_management.devdocs.json @@ -76,7 +76,7 @@ "signature": [ "\"ILM_LOCATOR_ID\"" ], - "path": "x-pack/plugins/index_lifecycle_management/public/locator.ts", + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index afdd2f43325b..2ac0dcfaf98a 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-06 +date: 2024-11-12 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 fc07f5e9d59a..3cbc9017267c 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/inference.mdx b/api_docs/inference.mdx index 3b990b0c3a69..5889e24b72ce 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inference'] --- import inferenceObj from './inference.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index f8a969160728..bb0c9357874c 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-06 +date: 2024-11-12 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 32b47085bdcb..8b52232dfdde 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-06 +date: 2024-11-12 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 dccfe71080cb..27ac4506fff0 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/integration_assistant.mdx b/api_docs/integration_assistant.mdx index f49cf1b365ab..ce73de5a54c4 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-06 +date: 2024-11-12 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 50416668f4df..fc5f400d8fcf 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-06 +date: 2024-11-12 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 acc804d84810..0e858f8be04a 100644 --- a/api_docs/inventory.devdocs.json +++ b/api_docs/inventory.devdocs.json @@ -128,7 +128,9 @@ "LiteralC", "<\"entity.type\">, ", "LiteralC", - "<\"alertsCount\">]>; sortDirection: ", + "<\"alertsCount\">, ", + "LiteralC", + "<\"actions\">]>; sortDirection: ", "UnionC", "<[", "LiteralC", diff --git a/api_docs/inventory.mdx b/api_docs/inventory.mdx index 947915c5c858..a990a02009d5 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-06 +date: 2024-11-12 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 468f5aba08fc..741c6e1c5114 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-06 +date: 2024-11-12 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 1ad9629c1601..f0ae814454ee 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-06 +date: 2024-11-12 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 23d243f3870d..323a0f2db579 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-06 +date: 2024-11-12 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 40a4d81e7d2f..b507eb315eda 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-06 +date: 2024-11-12 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 e2e80e404409..edacea1dc39f 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-06 +date: 2024-11-12 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.mdx b/api_docs/kbn_aiops_components.mdx index 16c79eadc55d..cc29b5ba5dfa 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_log_pattern_analysis.mdx b/api_docs/kbn_aiops_log_pattern_analysis.mdx index 79b19e18e25d..6a83be2ef6cc 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-06 +date: 2024-11-12 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 59856214286a..b6d2c0ec0a60 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-06 +date: 2024-11-12 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 d2e43132d3ba..a0a848dc35bd 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-06 +date: 2024-11-12 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 a1a0a27c3dca..73454eb6b033 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-06 +date: 2024-11-12 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 4303bdb6e47f..69d5ec23230a 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-06 +date: 2024-11-12 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 f3325a895c15..84c78d006a98 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-06 +date: 2024-11-12 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 f98e4f0031cd..c52f50b5e995 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-06 +date: 2024-11-12 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 fac8796c6e9e..9b7d661ebb62 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-06 +date: 2024-11-12 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.mdx b/api_docs/kbn_alerts_ui_shared.mdx index 71cec495e838..d57b0582b6a6 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-ui-shared'] --- import kbnAlertsUiSharedObj from './kbn_alerts_ui_shared.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index 5e910ff6a31c..b2ee2ae503c5 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-06 +date: 2024-11-12 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 8553d8f10da0..d82b56b24aeb 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-06 +date: 2024-11-12 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 411bd0e27e18..62d47b008ad5 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-06 +date: 2024-11-12 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 14a8ea562eef..065e099e353a 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-06 +date: 2024-11-12 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 0c0f99defe2e..9edda86620a6 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-06 +date: 2024-11-12 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 f0e6fc01b8db..b22847579b95 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-06 +date: 2024-11-12 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 e92f4b42ff01..f018b4dc4f25 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-06 +date: 2024-11-12 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 4a21019d037b..5b84cbd3e321 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-06 +date: 2024-11-12 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 977b066769fe..964a8d376ae0 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-06 +date: 2024-11-12 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 16b2eb4b939e..e93dd4df949e 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-06 +date: 2024-11-12 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 78239eee5e5c..3b4644bfed2b 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-06 +date: 2024-11-12 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 269fcf98e058..e20024ebcc43 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-06 +date: 2024-11-12 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 ba174bebb90b..4e2600cb02f1 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-06 +date: 2024-11-12 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 04aad66926fc..e1f2327ed732 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-06 +date: 2024-11-12 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 702f57ce2fca..d183f1aefe14 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-06 +date: 2024-11-12 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 b3b996408ccd..320ae236f19c 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-06 +date: 2024-11-12 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 18c3439afb5b..1804025bc6e2 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-06 +date: 2024-11-12 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 774bfa816f8b..2abd21bd4910 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-06 +date: 2024-11-12 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 db82b4520a79..f2165c99ee6a 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-06 +date: 2024-11-12 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 2cbba4fe0944..ca26b29a5504 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-06 +date: 2024-11-12 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 6c65d204aaa7..0716b421c75d 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-06 +date: 2024-11-12 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 de15aec7cf8d..6d608449b7e0 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-06 +date: 2024-11-12 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.mdx b/api_docs/kbn_cloud_security_posture.mdx index 1da3d91b93ba..5a39b4863ce8 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture'] --- import kbnCloudSecurityPostureObj from './kbn_cloud_security_posture.devdocs.json'; diff --git a/api_docs/kbn_cloud_security_posture_common.devdocs.json b/api_docs/kbn_cloud_security_posture_common.devdocs.json index 7a23e5f8cfbd..6c0ae2a2db8a 100644 --- a/api_docs/kbn_cloud_security_posture_common.devdocs.json +++ b/api_docs/kbn_cloud_security_posture_common.devdocs.json @@ -83,7 +83,7 @@ "label": "trackUiMetric", "description": [], "signature": [ - "(metricType: string, eventName: CloudSecurityUiCounters) => void" + "(metricType: string, eventName: string) => void" ], "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/ui_metrics.ts", "deprecated": false, @@ -107,12 +107,12 @@ { "parentPluginId": "@kbn/cloud-security-posture-common", "id": "def-common.UiMetricService.trackUiMetric.$2", - "type": "CompoundType", + "type": "string", "tags": [], "label": "eventName", "description": [], "signature": [ - "CloudSecurityUiCounters" + "string" ], "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/ui_metrics.ts", "deprecated": false, @@ -1547,7 +1547,7 @@ "label": "VulnSeverity", "description": [], "signature": [ - "\"UNKNOWN\" | \"LOW\" | \"MEDIUM\" | \"HIGH\" | \"CRITICAL\"" + "\"MEDIUM\" | \"UNKNOWN\" | \"LOW\" | \"HIGH\" | \"CRITICAL\"" ], "path": "x-pack/packages/kbn-cloud-security-posture/common/types/vulnerabilities.ts", "deprecated": false, diff --git a/api_docs/kbn_cloud_security_posture_common.mdx b/api_docs/kbn_cloud_security_posture_common.mdx index c6abfcc1da15..980f1e79d34c 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture-common'] --- import kbnCloudSecurityPostureCommonObj from './kbn_cloud_security_posture_common.devdocs.json'; diff --git a/api_docs/kbn_cloud_security_posture_graph.mdx b/api_docs/kbn_cloud_security_posture_graph.mdx index a83800135b8b..a9807078c177 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-06 +date: 2024-11-12 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 7c5e58bc09c9..353c1146fc6e 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-06 +date: 2024-11-12 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 4cd49ae807df..7b994f1c7fe5 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-06 +date: 2024-11-12 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 920b7fbe2096..c0502db23115 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-06 +date: 2024-11-12 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 d8270b3ac8d6..c38e34841f10 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-06 +date: 2024-11-12 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 8449100bf79c..36df67b11013 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-06 +date: 2024-11-12 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 873dad567ad4..64dc10df0c3a 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-06 +date: 2024-11-12 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 84816984da01..b150c48b02ad 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-06 +date: 2024-11-12 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 80c25017ad73..d23fabc9adf0 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-06 +date: 2024-11-12 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 f53ce023771a..1c65dad73ba5 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-06 +date: 2024-11-12 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 904071301683..12a392966e5c 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-06 +date: 2024-11-12 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_public.mdx b/api_docs/kbn_content_management_favorites_public.mdx index bdeac5ac2068..1bd4a4c16c00 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-06 +date: 2024-11-12 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 eb954f7d202d..1b8425c4c298 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-06 +date: 2024-11-12 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 38d0de9620f8..609458b5331d 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-06 +date: 2024-11-12 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 72e2e3b6267e..dc11375e8a81 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-06 +date: 2024-11-12 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 7bf9fdf272c0..c03a1ec3197c 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-06 +date: 2024-11-12 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 d9b1d32f77cb..db646bd36292 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-06 +date: 2024-11-12 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 ffe8ae55d341..74795dd1d890 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-06 +date: 2024-11-12 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 dfee350e60ec..d00fea0e055b 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-06 +date: 2024-11-12 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 288f48a4955a..16e5bf6680c4 100644 --- a/api_docs/kbn_core_analytics_browser.devdocs.json +++ b/api_docs/kbn_core_analytics_browser.devdocs.json @@ -702,9 +702,17 @@ "plugin": "datasetQuality", "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_client.ts" }, + { + "plugin": "@kbn/langchain", + "path": "x-pack/packages/kbn-langchain/server/tracers/telemetry/telemetry_tracer.ts" + }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts" + }, { "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/routes/helpers.ts" + "path": "x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts" }, { "plugin": "elasticAssistant", @@ -722,6 +730,10 @@ "plugin": "elasticAssistant", "path": "x-pack/plugins/elastic_assistant/server/routes/attack_discovery/post/helpers/handle_graph_error/index.tsx" }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts" + }, { "plugin": "globalSearchBar", "path": "x-pack/plugins/global_search_bar/public/telemetry/event_reporter.ts" @@ -796,151 +808,7 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.ts" }, { "plugin": "osquery", @@ -1170,6 +1038,14 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.test.ts" }, + { + "plugin": "@kbn/langchain", + "path": "x-pack/packages/kbn-langchain/server/tracers/telemetry/telemetry_tracer.test.ts" + }, + { + "plugin": "@kbn/langchain", + "path": "x-pack/packages/kbn-langchain/server/tracers/telemetry/telemetry_tracer.test.ts" + }, { "plugin": "@kbn/shared-ux-chrome-navigation", "path": "packages/shared-ux/chrome/navigation/mocks/storybook.ts" diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 08d6ae4b2c0b..9259732156ac 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-06 +date: 2024-11-12 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 c4e034a98fa5..aa45f95180ae 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-06 +date: 2024-11-12 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 932c4df060a5..c0bd6d0cd571 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-06 +date: 2024-11-12 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 c08c5dec164f..f4eedf0c5ca7 100644 --- a/api_docs/kbn_core_analytics_server.devdocs.json +++ b/api_docs/kbn_core_analytics_server.devdocs.json @@ -710,9 +710,17 @@ "plugin": "datasetQuality", "path": "x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/telemetry_client.ts" }, + { + "plugin": "@kbn/langchain", + "path": "x-pack/packages/kbn-langchain/server/tracers/telemetry/telemetry_tracer.ts" + }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts" + }, { "plugin": "elasticAssistant", - "path": "x-pack/plugins/elastic_assistant/server/routes/helpers.ts" + "path": "x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts" }, { "plugin": "elasticAssistant", @@ -730,6 +738,10 @@ "plugin": "elasticAssistant", "path": "x-pack/plugins/elastic_assistant/server/routes/attack_discovery/post/helpers/handle_graph_error/index.tsx" }, + { + "plugin": "elasticAssistant", + "path": "x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts" + }, { "plugin": "globalSearchBar", "path": "x-pack/plugins/global_search_bar/public/telemetry/event_reporter.ts" @@ -804,151 +816,7 @@ }, { "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts" + "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.ts" }, { "plugin": "osquery", @@ -1178,6 +1046,14 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/services/actions/clients/sentinelone/sentinel_one_actions_client.test.ts" }, + { + "plugin": "@kbn/langchain", + "path": "x-pack/packages/kbn-langchain/server/tracers/telemetry/telemetry_tracer.test.ts" + }, + { + "plugin": "@kbn/langchain", + "path": "x-pack/packages/kbn-langchain/server/tracers/telemetry/telemetry_tracer.test.ts" + }, { "plugin": "@kbn/shared-ux-chrome-navigation", "path": "packages/shared-ux/chrome/navigation/mocks/storybook.ts" diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index d7231d6acac4..ed1a968c83f5 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-06 +date: 2024-11-12 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 2309f9c5657c..a439349d60a6 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-06 +date: 2024-11-12 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 f4395a7f234c..04e2124bb9c9 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-06 +date: 2024-11-12 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 3d8474e494b2..c5bc8ea96ebb 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-06 +date: 2024-11-12 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 dbc19314ab03..8ca3a84902b6 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-06 +date: 2024-11-12 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 75729071682b..b092910766ce 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-06 +date: 2024-11-12 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 4fc3b5b44df4..8fbc068a4706 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-06 +date: 2024-11-12 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 58a9f17c8263..437494990ec6 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-06 +date: 2024-11-12 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 5630f5822d18..8360e30d6890 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-06 +date: 2024-11-12 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 329656a09591..cad169815e48 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-06 +date: 2024-11-12 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 c039ebc47fe7..74026cbd53e9 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-06 +date: 2024-11-12 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 b91c293f93cf..0240046659de 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-06 +date: 2024-11-12 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 790a3c6ba351..dd4240e077be 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-06 +date: 2024-11-12 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 4232fd927b7a..672f23c9f90d 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-06 +date: 2024-11-12 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 50c38360bc2b..c785a618c178 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-06 +date: 2024-11-12 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 10cbb3a42f71..746a4b1c7663 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-06 +date: 2024-11-12 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 21a636aa7ac3..aee86b190440 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-06 +date: 2024-11-12 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 02474a59d662..7cf4a32d639c 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser.devdocs.json b/api_docs/kbn_core_chrome_browser.devdocs.json index 33a27d209c1a..3c3be73393fd 100644 --- a/api_docs/kbn_core_chrome_browser.devdocs.json +++ b/api_docs/kbn_core_chrome_browser.devdocs.json @@ -3765,7 +3765,7 @@ "label": "AppDeepLinkId", "description": [], "signature": [ - "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" + "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\" | \"elasticsearchIndices:createIndex\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" ], "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", "deprecated": false, diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index e4e5f6c1af42..8032ac640544 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-06 +date: 2024-11-12 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 3f4208ad1ae0..75e2407cd10a 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-06 +date: 2024-11-12 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 e8afe9bd646a..a433a292166d 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-06 +date: 2024-11-12 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 8b9fd4b698d5..c55f6aebf24e 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-06 +date: 2024-11-12 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 c5ed9476efd2..264a15c21f09 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-06 +date: 2024-11-12 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 f5f1ada88d61..bc0608681fd2 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-06 +date: 2024-11-12 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 e86aa10a1917..d737e6e6ca44 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-06 +date: 2024-11-12 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 9a9d3b221f78..6ac8945bd5ed 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-06 +date: 2024-11-12 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 b93a08d18123..c1b509be36d7 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-06 +date: 2024-11-12 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 57d503043c1a..58a80bf9bfa8 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-06 +date: 2024-11-12 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 e6bcad717b40..2ae00993441d 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-06 +date: 2024-11-12 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 5d0a2c69423f..9242b3fdfeab 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-06 +date: 2024-11-12 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 2dbababad6f9..0bf08b893122 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-06 +date: 2024-11-12 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 c4649935ad98..1f739c5487f5 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-06 +date: 2024-11-12 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 4340e599c355..a5cccdd0d5a0 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-06 +date: 2024-11-12 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 9b8357be9bac..551be6ea0218 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-06 +date: 2024-11-12 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 304df9b7ce27..9a65ae1e2c5b 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-06 +date: 2024-11-12 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 358174bf8b25..4de0ca0c9cfb 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-06 +date: 2024-11-12 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 19ab96693b1b..80b3e3e26641 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-06 +date: 2024-11-12 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 fb5be4e5925d..b882e55e2868 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-06 +date: 2024-11-12 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 13c4847aa028..3c8ea9e8c466 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-06 +date: 2024-11-12 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 ca6aea74575b..84df80a37f93 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-06 +date: 2024-11-12 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 d33c950bd945..f50ca818415f 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-06 +date: 2024-11-12 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 07b3db79355a..c5826d203475 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-06 +date: 2024-11-12 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 681bfe2eaad3..2f73e097f7c9 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-06 +date: 2024-11-12 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 c6ebdec57597..fa7781332cfa 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-06 +date: 2024-11-12 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 d5eea9d1abb7..4c36b5581b46 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-06 +date: 2024-11-12 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 179efddfd19a..a0e64301bb79 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-06 +date: 2024-11-12 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 4f05b697d61c..6c9755570d2d 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-06 +date: 2024-11-12 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 509adf37d5b1..127df174a3bc 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-06 +date: 2024-11-12 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 522b02f2529e..30d224c19668 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-06 +date: 2024-11-12 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 014ba44b95b3..b9c20af8150d 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-06 +date: 2024-11-12 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 548fc4319cd8..d47ddada7166 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-06 +date: 2024-11-12 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 60371494c786..6ee19e86b582 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-06 +date: 2024-11-12 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 be55d839de8a..310c9bf7bd3e 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-06 +date: 2024-11-12 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 e91b03c2671b..679920d6b3db 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-06 +date: 2024-11-12 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 7d11e213801d..3e0bfcaa8304 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-06 +date: 2024-11-12 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 f22771ef52d1..793b33b79ab0 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-06 +date: 2024-11-12 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 0219e571cc5f..db78d3fe60e6 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-06 +date: 2024-11-12 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 2cee4edb6a1a..7d1fa5abe768 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-06 +date: 2024-11-12 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 6b0e9fc03be3..bbde0e51faad 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-06 +date: 2024-11-12 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 355fd7df8a76..a8258021ff78 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-06 +date: 2024-11-12 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 fbef6d8af8c3..e91372be6686 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-06 +date: 2024-11-12 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 fd25a2137512..db7d25304478 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-06 +date: 2024-11-12 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 4224b548fd4b..10cbd80fa71e 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-06 +date: 2024-11-12 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 a71c4f6dc0f7..9e0719fd6226 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-06 +date: 2024-11-12 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 f976a0ecb43a..f0cbb937bd0f 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-06 +date: 2024-11-12 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 3c5878bc9406..22a6fb73a4ae 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-06 +date: 2024-11-12 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 c62ab5cec766..555a50af31ce 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-06 +date: 2024-11-12 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 964c53a4d0f2..a5a3777f62ce 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-06 +date: 2024-11-12 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 c490e20d1fc1..8a68b7151014 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-06 +date: 2024-11-12 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 ccc7d7b74083..1e3c7b50cb54 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-06 +date: 2024-11-12 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 c76a88f272be..02094a11da01 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-06 +date: 2024-11-12 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 ec40c303395f..4e72693fbcae 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-06 +date: 2024-11-12 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 78a5ec9023ff..8211b20d63c7 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -410,7 +410,13 @@ "description": [], "signature": [ "{ deprecated?: ", - "RouteDeprecationInfo", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteDeprecationInfo", + "text": "RouteDeprecationInfo" + }, " | undefined; } | undefined" ], "path": "packages/core/http/core-http-server/src/versioning/types.ts", @@ -3863,6 +3869,14 @@ "plugin": "security", "path": "x-pack/plugins/security/server/routes/views/login.ts" }, + { + "plugin": "share", + "path": "src/plugins/share/server/url_service/http/short_urls/register_get_route.ts" + }, + { + "plugin": "share", + "path": "src/plugins/share/server/url_service/http/short_urls/register_resolve_route.ts" + }, { "plugin": "monitoringCollection", "path": "x-pack/plugins/monitoring_collection/server/routes/api/v1/dynamic_route/get_metrics_by_type.ts" @@ -3891,14 +3905,6 @@ "plugin": "actions", "path": "x-pack/plugins/actions/server/routes/connector/get/get.ts" }, - { - "plugin": "share", - "path": "src/plugins/share/server/url_service/http/short_urls/register_get_route.ts" - }, - { - "plugin": "share", - "path": "src/plugins/share/server/url_service/http/short_urls/register_resolve_route.ts" - }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/find.ts" @@ -4667,10 +4673,6 @@ "plugin": "logstash", "path": "x-pack/plugins/logstash/server/routes/pipelines/list.ts" }, - { - "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_types/timeseries/server/routes/fields.ts" - }, { "plugin": "metricsDataAccess", "path": "x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/kibana_framework_adapter.ts" @@ -4679,6 +4681,10 @@ "plugin": "metricsDataAccess", "path": "x-pack/plugins/observability_solution/metrics_data_access/server/routes/metric_indices/index.ts" }, + { + "plugin": "visTypeTimeseries", + "path": "src/plugins/vis_types/timeseries/server/routes/fields.ts" + }, { "plugin": "infra", "path": "x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" @@ -4699,10 +4705,6 @@ "plugin": "@kbn/test-suites-xpack", "path": "x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/jira_simulation.ts" }, - { - "plugin": "@kbn/test-suites-xpack", - "path": "x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/jira_simulation.ts" - }, { "plugin": "@kbn/test-suites-xpack", "path": "x-pack/test/alerting_api_integration/common/plugins/actions_simulators/server/resilient_simulation.ts" @@ -4879,6 +4881,10 @@ "plugin": "stackConnectors", "path": "x-pack/plugins/stack_connectors/server/routes/get_well_known_email_service.ts" }, + { + "plugin": "stackConnectors", + "path": "x-pack/plugins/stack_connectors/server/routes/get_inference_services.ts" + }, { "plugin": "upgradeAssistant", "path": "x-pack/plugins/upgrade_assistant/server/routes/reindex_indices/reindex_indices.ts" @@ -5307,6 +5313,10 @@ "plugin": "ruleRegistry", "path": "x-pack/plugins/rule_registry/server/routes/__mocks__/server.ts" }, + { + "plugin": "stackConnectors", + "path": "x-pack/plugins/stack_connectors/server/routes/get_inference_services.test.ts" + }, { "plugin": "stackConnectors", "path": "x-pack/plugins/stack_connectors/server/routes/get_well_known_email_service.test.ts" @@ -6493,14 +6503,18 @@ "plugin": "security", "path": "x-pack/plugins/security/server/routes/analytics/record_violations.ts" }, - { - "plugin": "serverless", - "path": "x-pack/plugins/serverless/server/plugin.ts" - }, { "plugin": "encryptedSavedObjects", "path": "x-pack/plugins/encrypted_saved_objects/server/routes/key_rotation.ts" }, + { + "plugin": "share", + "path": "src/plugins/share/server/url_service/http/short_urls/register_create_route.ts" + }, + { + "plugin": "serverless", + "path": "x-pack/plugins/serverless/server/plugin.ts" + }, { "plugin": "actions", "path": "x-pack/plugins/actions/server/routes/connector/create/create.ts" @@ -6521,10 +6535,6 @@ "plugin": "actions", "path": "x-pack/plugins/actions/server/routes/get_global_execution_kpi.ts" }, - { - "plugin": "share", - "path": "src/plugins/share/server/url_service/http/short_urls/register_create_route.ts" - }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/create.ts" @@ -7233,14 +7243,14 @@ "plugin": "logstash", "path": "x-pack/plugins/logstash/server/routes/pipelines/delete.ts" }, - { - "plugin": "visTypeTimeseries", - "path": "src/plugins/vis_types/timeseries/server/routes/vis.ts" - }, { "plugin": "metricsDataAccess", "path": "x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/kibana_framework_adapter.ts" }, + { + "plugin": "visTypeTimeseries", + "path": "src/plugins/vis_types/timeseries/server/routes/vis.ts" + }, { "plugin": "infra", "path": "x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/kibana_framework_adapter.ts" @@ -7329,10 +7339,6 @@ "plugin": "painlessLab", "path": "x-pack/plugins/painless_lab/server/routes/api/execute.ts" }, - { - "plugin": "reporting", - "path": "x-pack/plugins/reporting/server/routes/internal/generate/csv_searchsource_immediate.ts" - }, { "plugin": "reporting", "path": "x-pack/plugins/reporting/server/routes/internal/generate/generate_from_jobparams.ts" @@ -9679,14 +9685,14 @@ "plugin": "security", "path": "x-pack/plugins/security/server/routes/users/delete.ts" }, - { - "plugin": "actions", - "path": "x-pack/plugins/actions/server/routes/connector/delete/delete.ts" - }, { "plugin": "share", "path": "src/plugins/share/server/url_service/http/short_urls/register_delete_route.ts" }, + { + "plugin": "actions", + "path": "x-pack/plugins/actions/server/routes/connector/delete/delete.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/delete.ts" @@ -11731,7 +11737,13 @@ "label": "deprecated", "description": [], "signature": [ - "RouteDeprecationInfo", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteDeprecationInfo", + "text": "RouteDeprecationInfo" + }, " | undefined" ], "path": "packages/core/http/core-http-server/src/router/request.ts", @@ -13285,7 +13297,13 @@ "\nDescription of deprecations for this HTTP API.\n" ], "signature": [ - "RouteDeprecationInfo", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteDeprecationInfo", + "text": "RouteDeprecationInfo" + }, " | undefined" ], "path": "packages/core/http/core-http-server/src/router/route.ts", @@ -13492,6 +13510,83 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-server.RouteDeprecationInfo", + "type": "Interface", + "tags": [], + "label": "RouteDeprecationInfo", + "description": [ + "\nRoute Deprecation info\nThis information will assist Kibana HTTP API users when upgrading to new versions\nof the Elastic stack (via Upgrade Assistant) and will be surfaced in documentation\ncreated from HTTP API introspection (like OAS)." + ], + "path": "packages/core/http/core-http-server/src/router/route.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-server.RouteDeprecationInfo.documentationUrl", + "type": "string", + "tags": [], + "label": "documentationUrl", + "description": [ + "\nlink to the documentation for more details on the deprecation." + ], + "path": "packages/core/http/core-http-server/src/router/route.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-server.RouteDeprecationInfo.message", + "type": "string", + "tags": [], + "label": "message", + "description": [ + "\nThe description message to be displayed for the deprecation.\nCheck the README for writing deprecations in `src/core/server/deprecations/README.mdx`" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/core/http/core-http-server/src/router/route.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-server.RouteDeprecationInfo.severity", + "type": "CompoundType", + "tags": [], + "label": "severity", + "description": [ + "\nlevels:\n- warning: will not break deployment upon upgrade.\n- critical: needs to be addressed before upgrade." + ], + "signature": [ + "\"warning\" | \"critical\"" + ], + "path": "packages/core/http/core-http-server/src/router/route.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-http-server", + "id": "def-server.RouteDeprecationInfo.reason", + "type": "CompoundType", + "tags": [], + "label": "reason", + "description": [ + "\nAPI deprecation reason:\n- bump: New version of the API is available.\n- remove: API was fully removed with no replacement.\n- migrate: API has been migrated to a different path.\n- deprecated: the deprecated API is deprecated, it might be removed or migrated, or got a version bump in the future.\n It is a catch-all deprecation for APIs but the API will work in the next upgrades." + ], + "signature": [ + "VersionBumpDeprecationType | RemovalApiDeprecationType | MigrationApiDeprecationType | DeprecateApiDeprecationType" + ], + "path": "packages/core/http/core-http-server/src/router/route.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-http-server", "id": "def-server.RouterDeprecatedRouteDetails", @@ -13511,7 +13606,13 @@ "label": "routeDeprecationOptions", "description": [], "signature": [ - "RouteDeprecationInfo" + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteDeprecationInfo", + "text": "RouteDeprecationInfo" + } ], "path": "packages/core/http/core-http-server/src/router/router.ts", "deprecated": false, @@ -14951,6 +15052,10 @@ "plugin": "data", "path": "src/plugins/data/server/scripts/route.ts" }, + { + "plugin": "controls", + "path": "src/plugins/controls/server/options_list/options_list_cluster_settings_route.ts" + }, { "plugin": "@kbn/core-http-router-server-mocks", "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts" @@ -15599,6 +15704,14 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/risk_score/index_status/index.ts" }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/server/api/register_routes.ts" + }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/server/api/register_routes.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/tags/routes/get_tags_by_name.ts" @@ -15671,6 +15784,22 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/list.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/privileges.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/get.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/stats.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/stats_all.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts" @@ -15780,8 +15909,12 @@ "path": "x-pack/plugins/observability_solution/uptime/server/legacy_uptime/uptime_server.ts" }, { - "plugin": "controls", - "path": "src/plugins/controls/server/options_list/options_list_cluster_settings_route.ts" + "plugin": "dataUsage", + "path": "x-pack/plugins/data_usage/server/routes/internal/data_streams.test.ts" + }, + { + "plugin": "dataUsage", + "path": "x-pack/plugins/data_usage/server/routes/internal/data_streams.test.ts" }, { "plugin": "@kbn/core-http-router-server-internal", @@ -16182,10 +16315,22 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/create_script_route.ts" }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/server/api/register_routes.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/tags/routes/create_tag.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/start.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/stop.ts" + }, { "plugin": "transform", "path": "x-pack/plugins/transform/server/routes/api/transforms_create/register_route.ts" @@ -16413,6 +16558,10 @@ "plugin": "unifiedSearch", "path": "src/plugins/unified_search/server/autocomplete/value_suggestions_route.ts" }, + { + "plugin": "controls", + "path": "src/plugins/controls/server/options_list/options_list_suggestions_route.ts" + }, { "plugin": "@kbn/core-http-router-server-mocks", "path": "packages/core/http/core-http-router-server-mocks/src/versioned_router.mock.ts" @@ -17101,6 +17250,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/exceptions/api/manage_exceptions/route.ts" }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/server/api/register_routes.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/dashboards/routes/get_dashboards_by_tags.ts" @@ -17281,6 +17434,14 @@ "plugin": "synthetics", "path": "x-pack/plugins/observability_solution/synthetics/server/server.ts" }, + { + "plugin": "dataUsage", + "path": "x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts" + }, + { + "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" @@ -17293,10 +17454,6 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts" }, - { - "plugin": "controls", - "path": "src/plugins/controls/server/options_list/options_list_suggestions_route.ts" - }, { "plugin": "dataViewFieldEditor", "path": "src/plugins/data_view_field_editor/server/routes/field_preview.ts" @@ -17767,6 +17924,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/delete_script_route.ts" }, + { + "plugin": "dashboard", + "path": "src/plugins/dashboard/server/api/register_routes.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/timeline/routes/timelines/delete_timelines/index.ts" diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index a78901d76b41..c383d3d6e196 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 552 | 2 | 232 | 1 | +| 557 | 2 | 232 | 0 | ## Server diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 24b837de603d..83ee885d5b20 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-06 +date: 2024-11-12 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.devdocs.json b/api_docs/kbn_core_http_server_mocks.devdocs.json index ec3fe801a567..4943ddf7d824 100644 --- a/api_docs/kbn_core_http_server_mocks.devdocs.json +++ b/api_docs/kbn_core_http_server_mocks.devdocs.json @@ -638,7 +638,13 @@ "[], [], unknown>; registerOnPostValidation: jest.MockInstance, metadata: { deprecated: ", - "RouteDeprecationInfo", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteDeprecationInfo", + "text": "RouteDeprecationInfo" + }, "; }) => void], unknown>; registerRouterAfterListening: jest.MockInstance void" + ", { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies) => void" ], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_create.ts", "deprecated": false, @@ -198,7 +198,7 @@ "id": "def-server.registerBulkCreateRoute.$2", "type": "Object", "tags": [], - "label": "{ config, coreUsageData, logger, access }", + "label": "{ config, coreUsageData, logger, access, deprecationInfo }", "description": [], "signature": [ "RouteDependencies" @@ -222,7 +222,7 @@ "signature": [ "(router: ", "InternalSavedObjectRouter", - ", { config, coreUsageData, logger, access }: RouteDependencies) => void" + ", { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies) => void" ], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_delete.ts", "deprecated": false, @@ -248,7 +248,7 @@ "id": "def-server.registerBulkDeleteRoute.$2", "type": "Object", "tags": [], - "label": "{ config, coreUsageData, logger, access }", + "label": "{ config, coreUsageData, logger, access, deprecationInfo }", "description": [], "signature": [ "RouteDependencies" @@ -272,7 +272,7 @@ "signature": [ "(router: ", "InternalSavedObjectRouter", - ", { config, coreUsageData, logger, access }: RouteDependencies) => void" + ", { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies) => void" ], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_get.ts", "deprecated": false, @@ -298,7 +298,7 @@ "id": "def-server.registerBulkGetRoute.$2", "type": "Object", "tags": [], - "label": "{ config, coreUsageData, logger, access }", + "label": "{ config, coreUsageData, logger, access, deprecationInfo }", "description": [], "signature": [ "RouteDependencies" @@ -322,7 +322,7 @@ "signature": [ "(router: ", "InternalSavedObjectRouter", - ", { config, coreUsageData, logger, access }: RouteDependencies) => void" + ", { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies) => void" ], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_resolve.ts", "deprecated": false, @@ -348,7 +348,7 @@ "id": "def-server.registerBulkResolveRoute.$2", "type": "Object", "tags": [], - "label": "{ config, coreUsageData, logger, access }", + "label": "{ config, coreUsageData, logger, access, deprecationInfo }", "description": [], "signature": [ "RouteDependencies" @@ -372,7 +372,7 @@ "signature": [ "(router: ", "InternalSavedObjectRouter", - ", { config, coreUsageData, logger, access }: RouteDependencies) => void" + ", { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies) => void" ], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_update.ts", "deprecated": false, @@ -398,7 +398,7 @@ "id": "def-server.registerBulkUpdateRoute.$2", "type": "Object", "tags": [], - "label": "{ config, coreUsageData, logger, access }", + "label": "{ config, coreUsageData, logger, access, deprecationInfo }", "description": [], "signature": [ "RouteDependencies" @@ -422,7 +422,7 @@ "signature": [ "(router: ", "InternalSavedObjectRouter", - ", { config, coreUsageData, logger, access }: RouteDependencies) => void" + ", { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies) => void" ], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/create.ts", "deprecated": false, @@ -448,7 +448,7 @@ "id": "def-server.registerCreateRoute.$2", "type": "Object", "tags": [], - "label": "{ config, coreUsageData, logger, access }", + "label": "{ config, coreUsageData, logger, access, deprecationInfo }", "description": [], "signature": [ "RouteDependencies" @@ -472,7 +472,7 @@ "signature": [ "(router: ", "InternalSavedObjectRouter", - ", { config, coreUsageData, logger, access }: RouteDependencies) => void" + ", { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies) => void" ], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/delete.ts", "deprecated": false, @@ -498,7 +498,7 @@ "id": "def-server.registerDeleteRoute.$2", "type": "Object", "tags": [], - "label": "{ config, coreUsageData, logger, access }", + "label": "{ config, coreUsageData, logger, access, deprecationInfo }", "description": [], "signature": [ "RouteDependencies" @@ -622,7 +622,7 @@ "signature": [ "(router: ", "InternalSavedObjectRouter", - ", { config, coreUsageData, logger, access }: RouteDependencies) => void" + ", { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies) => void" ], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/find.ts", "deprecated": false, @@ -648,7 +648,7 @@ "id": "def-server.registerFindRoute.$2", "type": "Object", "tags": [], - "label": "{ config, coreUsageData, logger, access }", + "label": "{ config, coreUsageData, logger, access, deprecationInfo }", "description": [], "signature": [ "RouteDependencies" @@ -672,7 +672,7 @@ "signature": [ "(router: ", "InternalSavedObjectRouter", - ", { config, coreUsageData, logger, access }: RouteDependencies) => void" + ", { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies) => void" ], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/get.ts", "deprecated": false, @@ -698,7 +698,7 @@ "id": "def-server.registerGetRoute.$2", "type": "Object", "tags": [], - "label": "{ config, coreUsageData, logger, access }", + "label": "{ config, coreUsageData, logger, access, deprecationInfo }", "description": [], "signature": [ "RouteDependencies" @@ -772,7 +772,7 @@ "signature": [ "(router: ", "InternalSavedObjectRouter", - ", { kibanaVersion, coreUsageData, logger, access, }: { kibanaVersion: string; coreUsageData: ", + ", { kibanaVersion, coreUsageData, logger, access, legacyDeprecationInfo, }: { kibanaVersion: string; coreUsageData: ", "InternalCoreUsageDataSetup", "; logger: ", { @@ -790,6 +790,14 @@ "section": "def-server.RouteAccess", "text": "RouteAccess" }, + "; legacyDeprecationInfo: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteDeprecationInfo", + "text": "RouteDeprecationInfo" + }, "; }) => void" ], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/export.ts", @@ -816,7 +824,7 @@ "id": "def-server.registerLegacyExportRoute.$2", "type": "Object", "tags": [], - "label": "{\n kibanaVersion,\n coreUsageData,\n logger,\n access,\n }", + "label": "{\n kibanaVersion,\n coreUsageData,\n logger,\n access,\n legacyDeprecationInfo,\n }", "description": [], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/export.ts", "deprecated": false, @@ -880,6 +888,26 @@ "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/export.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-server-internal", + "id": "def-server.registerLegacyExportRoute.$2.legacyDeprecationInfo", + "type": "Object", + "tags": [], + "label": "legacyDeprecationInfo", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteDeprecationInfo", + "text": "RouteDeprecationInfo" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/export.ts", + "deprecated": false, + "trackAdoption": false } ] } @@ -897,7 +925,7 @@ "signature": [ "(router: ", "InternalSavedObjectRouter", - ", { maxImportPayloadBytes, coreUsageData, logger, access, }: { maxImportPayloadBytes: number; coreUsageData: ", + ", { maxImportPayloadBytes, coreUsageData, logger, access, legacyDeprecationInfo, }: { maxImportPayloadBytes: number; coreUsageData: ", "InternalCoreUsageDataSetup", "; logger: ", { @@ -915,6 +943,14 @@ "section": "def-server.RouteAccess", "text": "RouteAccess" }, + "; legacyDeprecationInfo: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteDeprecationInfo", + "text": "RouteDeprecationInfo" + }, "; }) => void" ], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/import.ts", @@ -941,7 +977,7 @@ "id": "def-server.registerLegacyImportRoute.$2", "type": "Object", "tags": [], - "label": "{\n maxImportPayloadBytes,\n coreUsageData,\n logger,\n access,\n }", + "label": "{\n maxImportPayloadBytes,\n coreUsageData,\n logger,\n access,\n legacyDeprecationInfo,\n }", "description": [], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/import.ts", "deprecated": false, @@ -1005,6 +1041,26 @@ "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/import.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-server-internal", + "id": "def-server.registerLegacyImportRoute.$2.legacyDeprecationInfo", + "type": "Object", + "tags": [], + "label": "legacyDeprecationInfo", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteDeprecationInfo", + "text": "RouteDeprecationInfo" + } + ], + "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/import.ts", + "deprecated": false, + "trackAdoption": false } ] } @@ -1126,7 +1182,7 @@ "signature": [ "(router: ", "InternalSavedObjectRouter", - ", { config, coreUsageData, logger, access }: RouteDependencies) => void" + ", { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies) => void" ], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/resolve.ts", "deprecated": false, @@ -1152,7 +1208,7 @@ "id": "def-server.registerResolveRoute.$2", "type": "Object", "tags": [], - "label": "{ config, coreUsageData, logger, access }", + "label": "{ config, coreUsageData, logger, access, deprecationInfo }", "description": [], "signature": [ "RouteDependencies" @@ -1176,7 +1232,7 @@ "signature": [ "(router: ", "InternalSavedObjectRouter", - ", { config, coreUsageData, logger, access }: RouteDependencies) => void" + ", { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies) => void" ], "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/routes/update.ts", "deprecated": false, @@ -1202,7 +1258,7 @@ "id": "def-server.registerUpdateRoute.$2", "type": "Object", "tags": [], - "label": "{ config, coreUsageData, logger, access }", + "label": "{ config, coreUsageData, logger, access, deprecationInfo }", "description": [], "signature": [ "RouteDependencies" diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index 9f3a3691603b..f842bc5c03f2 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-internal'] --- import kbnCoreSavedObjectsServerInternalObj from './kbn_core_saved_objects_server_internal.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 73 | 0 | 72 | 5 | +| 75 | 0 | 74 | 5 | ## Server diff --git a/api_docs/kbn_core_saved_objects_server_mocks.mdx b/api_docs/kbn_core_saved_objects_server_mocks.mdx index 02b60f7eb0d3..483ac1602b82 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-06 +date: 2024-11-12 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 725c25d09e1f..403a2a37c289 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-06 +date: 2024-11-12 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 d0ae9eefbf4f..0dcb447e8fee 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-06 +date: 2024-11-12 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 eba9bca6d095..e55d56082469 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-06 +date: 2024-11-12 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 edcb33afa9fd..fd8915f08c0c 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-06 +date: 2024-11-12 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 c0dbcbb4dd4e..e8d59c0a1a20 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-06 +date: 2024-11-12 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 173b9fff4634..44f101b0964f 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-06 +date: 2024-11-12 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 3f2ebd5e061e..5c61fb024f1b 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-06 +date: 2024-11-12 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 df4af097e14f..10fb8ff1e098 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-06 +date: 2024-11-12 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 4aafadc33d8a..5ae33f158714 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common'] --- import kbnCoreStatusCommonObj from './kbn_core_status_common.devdocs.json'; diff --git a/api_docs/kbn_core_status_common_internal.mdx b/api_docs/kbn_core_status_common_internal.mdx index 296485874d52..cef994182b97 100644 --- a/api_docs/kbn_core_status_common_internal.mdx +++ b/api_docs/kbn_core_status_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common-internal title: "@kbn/core-status-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common-internal plugin -date: 2024-11-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common-internal'] --- import kbnCoreStatusCommonInternalObj from './kbn_core_status_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server.mdx b/api_docs/kbn_core_status_server.mdx index 9cccfd6f9216..b2b2cb7b568f 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-06 +date: 2024-11-12 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 9486bfafcd97..ef527c950cd3 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-06 +date: 2024-11-12 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 f5bb2c646b8e..938f83007fbc 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-06 +date: 2024-11-12 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 ef636613b326..a50c3b1828d6 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-06 +date: 2024-11-12 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 ef3dde73cc67..6a4b625285f0 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-06 +date: 2024-11-12 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 919b655271ff..02c5352bd4d1 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-06 +date: 2024-11-12 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 d209bb1d42cf..8aaf6a5f2adf 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-06 +date: 2024-11-12 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 e9dbf21b94eb..6aa9349a0352 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-06 +date: 2024-11-12 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 f20844bb6a3e..87b2f6d5c939 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-06 +date: 2024-11-12 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 2541f837f8bd..32ecd45349e1 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-06 +date: 2024-11-12 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 7ce99e5f4b54..4cbeda7788db 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-06 +date: 2024-11-12 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 550bb289571f..d953b935075e 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-06 +date: 2024-11-12 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 e291b5b0ef2e..fff46b5326d0 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-06 +date: 2024-11-12 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 2adc93b74797..53cf35bd07a4 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-06 +date: 2024-11-12 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 895ccb71bd3f..d038ab88a60a 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-06 +date: 2024-11-12 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 936c9871d1e1..b3a3706f5914 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-06 +date: 2024-11-12 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 a9221d42c90b..a2556a776c14 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-06 +date: 2024-11-12 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 6d47071ffe6d..f5e222efbd2b 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-06 +date: 2024-11-12 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 1dfb4a3e34ab..a4f5b11d8bdb 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-06 +date: 2024-11-12 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 158251df07e0..54002865f12d 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-06 +date: 2024-11-12 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 60f66a50a785..9e0390f9284c 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-06 +date: 2024-11-12 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 2853909368a5..c46f4f10e0e5 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-06 +date: 2024-11-12 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 e4036b359f45..f6e6a8b57420 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-06 +date: 2024-11-12 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 d181abea38e6..9d342ea1d869 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-06 +date: 2024-11-12 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 a547a652f841..c86d118151f0 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-06 +date: 2024-11-12 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 7c5c109349b9..4e32a6961089 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-06 +date: 2024-11-12 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 efc8aca4aaf7..b2e719a02d6b 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-06 +date: 2024-11-12 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 7f0f79c0d61b..44c3d2ffb345 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-06 +date: 2024-11-12 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 979e7ea2ee32..88c82c120c85 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-06 +date: 2024-11-12 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 f19ee3ccf165..85949052d0c4 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-06 +date: 2024-11-12 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 a17b5b14b12a..46e178ce0b71 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-06 +date: 2024-11-12 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 91d9c1f23d12..f118affa95cd 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-06 +date: 2024-11-12 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 de88984974dc..e663abed4b7e 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-06 +date: 2024-11-12 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 ce12ee6c8334..c5bcf7da108b 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-06 +date: 2024-11-12 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 764ee0db2bc3..05a5dbabe2df 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-06 +date: 2024-11-12 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 3e6244701fb2..a8388fdda54c 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-06 +date: 2024-11-12 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 c880ae8029b3..ab42e4e76223 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-06 +date: 2024-11-12 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 b2eb038389fc..d4e94e43d07e 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-06 +date: 2024-11-12 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 e6618be7b9a7..44350ffee001 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-06 +date: 2024-11-12 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 6d63bc1862dc..53b25850f8df 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-06 +date: 2024-11-12 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 1e40c1f000aa..9af32e7352b2 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-06 +date: 2024-11-12 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 5f051970f0f9..7190eea79989 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-06 +date: 2024-11-12 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 1815255e1c27..9b6d2bef5fca 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-06 +date: 2024-11-12 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 28cbfafd8c27..64a284f83f05 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-06 +date: 2024-11-12 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 0151cdad1e2d..46c0550d1e33 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-06 +date: 2024-11-12 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 c37364413c38..7dfd297037c5 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-observability'] --- import kbnDeeplinksObservabilityObj from './kbn_deeplinks_observability.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_search.devdocs.json b/api_docs/kbn_deeplinks_search.devdocs.json index d8cd4e993a4e..22c6f9258754 100644 --- a/api_docs/kbn_deeplinks_search.devdocs.json +++ b/api_docs/kbn_deeplinks_search.devdocs.json @@ -30,7 +30,7 @@ "label": "DeepLinkId", "description": [], "signature": [ - "\"appSearch\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\"" + "\"appSearch\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\" | \"elasticsearchIndices:createIndex\"" ], "path": "packages/deeplinks/search/deep_links.ts", "deprecated": false, diff --git a/api_docs/kbn_deeplinks_search.mdx b/api_docs/kbn_deeplinks_search.mdx index 4611016c5731..595d9fe34f8d 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-06 +date: 2024-11-12 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 7ba0fe30a691..c8972591f99c 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-06 +date: 2024-11-12 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 e93942bd13da..3aaefdeed692 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-06 +date: 2024-11-12 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 755d380fc704..3ec8e4ffe178 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-06 +date: 2024-11-12 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 4651fe94505b..938aac32af48 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-06 +date: 2024-11-12 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 b116cfc74165..6a1a579bcc4e 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-06 +date: 2024-11-12 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 4afee494882d..d68d42a1fbc3 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-06 +date: 2024-11-12 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 e608b8f6b73d..864f684cd5d6 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-06 +date: 2024-11-12 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 d272d3485013..2f83a9993ece 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-06 +date: 2024-11-12 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 d0564614550c..dbf2659bfd26 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-06 +date: 2024-11-12 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 ea6af279c45b..99b18514c257 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-06 +date: 2024-11-12 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.devdocs.json b/api_docs/kbn_discover_contextual_components.devdocs.json index b987fc426742..cd6c2ab526e2 100644 --- a/api_docs/kbn_discover_contextual_components.devdocs.json +++ b/api_docs/kbn_discover_contextual_components.devdocs.json @@ -174,9 +174,9 @@ "ExplainExplanation", " | undefined; highlight?: Record | undefined; inner_hits?: Record | undefined; matched_queries?: string[] | undefined; _nested?: ", + "> | undefined; matched_queries?: string[] | Record | undefined; _nested?: ", "SearchNestedIdentity", - " | undefined; _ignored?: string[] | undefined; ignored_field_values?: Record | undefined; _shard?: string | undefined; _node?: string | undefined; _routing?: string | undefined; _rank?: number | undefined; _seq_no?: number | undefined; _primary_term?: number | undefined; _version?: number | undefined; }; id: string; isAnchor?: boolean | undefined; }" + " | undefined; _ignored?: string[] | undefined; ignored_field_values?: Record | undefined; _shard?: string | undefined; _node?: string | undefined; _routing?: string | undefined; _rank?: number | undefined; _seq_no?: number | undefined; _primary_term?: number | undefined; _version?: number | undefined; }; id: string; isAnchor?: boolean | undefined; }" ], "path": "packages/kbn-discover-contextual-components/src/data_types/logs/components/summary_column/utils.tsx", "deprecated": false, diff --git a/api_docs/kbn_discover_contextual_components.mdx b/api_docs/kbn_discover_contextual_components.mdx index 2219c6cb0c92..68e6317d384e 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-06 +date: 2024-11-12 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 a889177a228f..ec4e0bd3901b 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-06 +date: 2024-11-12 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 592d2f62a236..d5942a032f31 100644 --- a/api_docs/kbn_doc_links.devdocs.json +++ b/api_docs/kbn_doc_links.devdocs.json @@ -476,7 +476,7 @@ "label": "kibana", "description": [], "signature": [ - "{ readonly askElastic: string; readonly createGithubIssue: string; readonly feedback: string; readonly guide: string; readonly autocompleteSuggestions: string; readonly secureSavedObject: string; readonly xpackSecurity: string; }" + "{ readonly askElastic: string; readonly createGithubIssue: string; readonly feedback: string; readonly guide: string; readonly autocompleteSuggestions: string; readonly secureSavedObject: string; readonly xpackSecurity: string; readonly dashboardImportExport: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index b135f6d5f0f2..0ef234ad26dc 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index 1ea80de173be..100e0358119e 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-06 +date: 2024-11-12 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 ca1793e12264..50724896d794 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-06 +date: 2024-11-12 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 5cd30ab7a056..60105e01565f 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-06 +date: 2024-11-12 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 c7b6b1d6e06b..2a958b1dc9ac 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-06 +date: 2024-11-12 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 9255f328835d..b9658cbf5597 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-06 +date: 2024-11-12 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.mdx b/api_docs/kbn_elastic_assistant.mdx index 50929b20864a..81b029f25b45 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant_common.mdx b/api_docs/kbn_elastic_assistant_common.mdx index cdb8d7987e67..1bd5f4dc7852 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-06 +date: 2024-11-12 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.mdx b/api_docs/kbn_entities_schema.mdx index b826e501998b..a1cae02d138d 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/entities-schema'] --- import kbnEntitiesSchemaObj from './kbn_entities_schema.devdocs.json'; diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index d445a6003763..167bbfa298fd 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-06 +date: 2024-11-12 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 8566e3b74dd4..2df4b2919483 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-06 +date: 2024-11-12 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 825595bb9603..8cba7dad7d05 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-06 +date: 2024-11-12 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 24d299c1ede0..7e3765672afd 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.devdocs.json b/api_docs/kbn_es_types.devdocs.json index d9baac147e26..60ef30c14df1 100644 --- a/api_docs/kbn_es_types.devdocs.json +++ b/api_docs/kbn_es_types.devdocs.json @@ -493,6 +493,8 @@ "AggregationsRateAggregation", "; reverse_nested: ", "AggregationsReverseNestedAggregation", + "; random_sampler: ", + "AggregationsRandomSamplerAggregation", "; sampler: ", "AggregationsSamplerAggregation", "; scripted_metric: ", @@ -515,6 +517,8 @@ "AggregationsSumBucketAggregation", "; terms: ", "AggregationsTermsAggregation", + "; time_series: ", + "AggregationsTimeSeriesAggregation", "; top_hits: ", "AggregationsTopHitsAggregation", "; t_test: ", diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index a7c6cd220b2f..3008d0904925 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-06 +date: 2024-11-12 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 25394de801af..9ad9028b3f58 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-06 +date: 2024-11-12 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 94ef986f9809..369dcc4b6cc1 100644 --- a/api_docs/kbn_esql_ast.devdocs.json +++ b/api_docs/kbn_esql_ast.devdocs.json @@ -2094,6 +2094,52 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.Walker.walkColumn", + "type": "Function", + "tags": [], + "label": "walkColumn", + "description": [], + "signature": [ + "(node: ", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLColumn", + "text": "ESQLColumn" + }, + ") => void" + ], + "path": "packages/kbn-esql-ast/src/walker/walker.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.Walker.walkColumn.$1", + "type": "Object", + "tags": [], + "label": "node", + "description": [], + "signature": [ + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLColumn", + "text": "ESQLColumn" + } + ], + "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", @@ -17696,6 +17742,26 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.ESQLColumn.args", + "type": "Array", + "tags": [], + "label": "args", + "description": [ + "\nA ES|QL column name can be composed of multiple parts,\ne.g: part1.part2.`part``3️⃣`.?param. Where parts can be quoted, or not\nquoted, or even be a parameter.\n\nThe args list contains the parts of the column name." + ], + "signature": [ + "(", + "ESQLIdentifier", + " | ", + "ESQLParam", + ")[]" + ], + "path": "packages/kbn-esql-ast/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/esql-ast", "id": "def-common.ESQLColumn.parts", @@ -19097,6 +19163,40 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.WalkerOptions.visitIdentifier", + "type": "Function", + "tags": [], + "label": "visitIdentifier", + "description": [], + "signature": [ + "((node: ", + "ESQLIdentifier", + ") => void) | undefined" + ], + "path": "packages/kbn-esql-ast/src/walker/walker.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.WalkerOptions.visitIdentifier.$1", + "type": "Object", + "tags": [], + "label": "node", + "description": [], + "signature": [ + "ESQLIdentifier" + ], + "path": "packages/kbn-esql-ast/src/walker/walker.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "@kbn/esql-ast", "id": "def-common.WalkerOptions.visitAny", @@ -19899,6 +19999,53 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.LeafPrinter.param", + "type": "Function", + "tags": [], + "label": "param", + "description": [], + "signature": [ + "(node: ", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLParamLiteral", + "text": "ESQLParamLiteral" + }, + ") => 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.param.$1", + "type": "Object", + "tags": [], + "label": "node", + "description": [], + "signature": [ + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLParamLiteral", + "text": "ESQLParamLiteral" + }, + "" + ], + "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.timeInterval", diff --git a/api_docs/kbn_esql_ast.mdx b/api_docs/kbn_esql_ast.mdx index e029abe42fa8..c1ec12593685 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-06 +date: 2024-11-12 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 | |-------------------|-----------|------------------------|-----------------| -| 270 | 1 | 211 | 35 | +| 277 | 1 | 217 | 36 | ## Common diff --git a/api_docs/kbn_esql_editor.mdx b/api_docs/kbn_esql_editor.mdx index c5abb2897dc9..0623f4544296 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-06 +date: 2024-11-12 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 2beb7a08ec73..606cd098419e 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-06 +date: 2024-11-12 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.devdocs.json b/api_docs/kbn_esql_validation_autocomplete.devdocs.json index a64d302db71b..78ca48d89df5 100644 --- a/api_docs/kbn_esql_validation_autocomplete.devdocs.json +++ b/api_docs/kbn_esql_validation_autocomplete.devdocs.json @@ -1041,7 +1041,7 @@ "\nThis function returns the variable or field matching a column" ], "signature": [ - "(column: ", + "(node: ", { "pluginId": "@kbn/esql-ast", "scope": "common", @@ -1049,6 +1049,8 @@ "section": "def-common.ESQLColumn", "text": "ESQLColumn" }, + " | ", + "ESQLIdentifier", ", { fields, variables }: Pick<", "ReferenceMaps", ", \"fields\" | \"variables\">) => ", @@ -1076,9 +1078,9 @@ { "parentPluginId": "@kbn/esql-validation-autocomplete", "id": "def-common.getColumnForASTNode.$1", - "type": "Object", + "type": "CompoundType", "tags": [], - "label": "column", + "label": "node", "description": [], "signature": [ { @@ -1087,7 +1089,9 @@ "docId": "kibKbnEsqlAstPluginApi", "section": "def-common.ESQLColumn", "text": "ESQLColumn" - } + }, + " | ", + "ESQLIdentifier" ], "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", "deprecated": false, diff --git a/api_docs/kbn_esql_validation_autocomplete.mdx b/api_docs/kbn_esql_validation_autocomplete.mdx index 16613b094569..bdda8ed94622 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-06 +date: 2024-11-12 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 cd55ee6de291..71ac2174e691 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-06 +date: 2024-11-12 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 7bd229a97727..ee224c8deeed 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-components'] --- import kbnEventAnnotationComponentsObj from './kbn_event_annotation_components.devdocs.json'; diff --git a/api_docs/kbn_expandable_flyout.mdx b/api_docs/kbn_expandable_flyout.mdx index 9f050e6312f6..5431633de245 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/expandable-flyout'] --- import kbnExpandableFlyoutObj from './kbn_expandable_flyout.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 1b6d4c8b2867..69e7372f4de5 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-06 +date: 2024-11-12 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 a9159e701d73..a69e34702878 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-06 +date: 2024-11-12 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 0422ff1833b1..dc8f6b7f3be1 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-06 +date: 2024-11-12 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 fe208fd75aed..36d81b43db66 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/formatters'] --- import kbnFormattersObj from './kbn_formatters.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_services.devdocs.json b/api_docs/kbn_ftr_common_functional_services.devdocs.json index da4cb9fdb2ab..d7fea06c3d9c 100644 --- a/api_docs/kbn_ftr_common_functional_services.devdocs.json +++ b/api_docs/kbn_ftr_common_functional_services.devdocs.json @@ -18,89 +18,6 @@ }, "common": { "classes": [ - { - "parentPluginId": "@kbn/ftr-common-functional-services", - "id": "def-common.BsearchService", - "type": "Class", - "tags": [], - "label": "BsearchService", - "description": [ - "\nBsearch Service that can reduce flake on the CI systems when they are under\npressure and bsearch returns an async search response or a sync response.\n" - ], - "signature": [ - { - "pluginId": "@kbn/ftr-common-functional-services", - "scope": "common", - "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" - }, - " extends ", - "FtrService" - ], - "path": "packages/kbn-ftr-common-functional-services/services/bsearch.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/ftr-common-functional-services", - "id": "def-common.BsearchService.send", - "type": "Function", - "tags": [], - "label": "send", - "description": [ - "Send method to send in your supertest, url, options, and strategy name" - ], - "signature": [ - ">({ supertest, options, strategy, space }: ", - { - "pluginId": "@kbn/ftr-common-functional-services", - "scope": "common", - "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.SendOptions", - "text": "SendOptions" - }, - ") => Promise" - ], - "path": "packages/kbn-ftr-common-functional-services/services/bsearch.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/ftr-common-functional-services", - "id": "def-common.BsearchService.send.$1", - "type": "Object", - "tags": [], - "label": "{ supertest, options, strategy, space }", - "description": [], - "signature": [ - { - "pluginId": "@kbn/ftr-common-functional-services", - "scope": "common", - "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.SendOptions", - "text": "SendOptions" - } - ], - "path": "packages/kbn-ftr-common-functional-services/services/bsearch.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - } - ], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/ftr-common-functional-services", "id": "def-common.DeploymentService", @@ -984,6 +901,89 @@ } ], "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/ftr-common-functional-services", + "id": "def-common.SearchService", + "type": "Class", + "tags": [], + "label": "SearchService", + "description": [ + "\nSearch Service that can reduce flake on the CI systems when they are under\npressure and search returns an async search response or a sync response.\n" + ], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", + "section": "def-common.SearchService", + "text": "SearchService" + }, + " extends ", + "FtrService" + ], + "path": "packages/kbn-ftr-common-functional-services/services/search.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-services", + "id": "def-common.SearchService.send", + "type": "Function", + "tags": [], + "label": "send", + "description": [ + "Send method to send in your supertest, url, options, and strategy name" + ], + "signature": [ + ">({ supertest, options, strategy, space }: ", + { + "pluginId": "@kbn/ftr-common-functional-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", + "section": "def-common.SendOptions", + "text": "SendOptions" + }, + ") => Promise" + ], + "path": "packages/kbn-ftr-common-functional-services/services/search.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/ftr-common-functional-services", + "id": "def-common.SearchService.send.$1", + "type": "Object", + "tags": [], + "label": "{ supertest, options, strategy, space }", + "description": [], + "signature": [ + { + "pluginId": "@kbn/ftr-common-functional-services", + "scope": "common", + "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", + "section": "def-common.SendOptions", + "text": "SendOptions" + } + ], + "path": "packages/kbn-ftr-common-functional-services/services/search.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false } ], "functions": [ @@ -1336,7 +1336,7 @@ "description": [ "\nOptions for the send method" ], - "path": "packages/kbn-ftr-common-functional-services/services/bsearch.ts", + "path": "packages/kbn-ftr-common-functional-services/services/search.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -1350,7 +1350,7 @@ "signature": [ "Agent" ], - "path": "packages/kbn-ftr-common-functional-services/services/bsearch.ts", + "path": "packages/kbn-ftr-common-functional-services/services/search.ts", "deprecated": false, "trackAdoption": false }, @@ -1364,7 +1364,7 @@ "signature": [ "object" ], - "path": "packages/kbn-ftr-common-functional-services/services/bsearch.ts", + "path": "packages/kbn-ftr-common-functional-services/services/search.ts", "deprecated": false, "trackAdoption": false }, @@ -1375,7 +1375,7 @@ "tags": [], "label": "strategy", "description": [], - "path": "packages/kbn-ftr-common-functional-services/services/bsearch.ts", + "path": "packages/kbn-ftr-common-functional-services/services/search.ts", "deprecated": false, "trackAdoption": false }, @@ -1389,7 +1389,7 @@ "signature": [ "string | undefined" ], - "path": "packages/kbn-ftr-common-functional-services/services/bsearch.ts", + "path": "packages/kbn-ftr-common-functional-services/services/search.ts", "deprecated": false, "trackAdoption": false } @@ -1544,13 +1544,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -1608,7 +1608,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -1740,13 +1756,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -1804,7 +1820,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -1937,7 +1969,23 @@ "label": "SamlAuthProviderType", "description": [], "signature": [ - "{ getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + "{ getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -2114,13 +2162,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -2178,7 +2226,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -2310,13 +2374,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -2374,7 +2438,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -2559,13 +2639,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -2623,7 +2703,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -2755,13 +2851,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -2819,7 +2915,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -3004,13 +3116,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -3068,7 +3180,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -3200,13 +3328,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -3264,7 +3392,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -3377,10 +3521,10 @@ }, { "parentPluginId": "@kbn/ftr-common-functional-services", - "id": "def-common.services.bsearch", + "id": "def-common.services.search", "type": "Object", "tags": [], - "label": "bsearch", + "label": "search", "description": [], "signature": [ "typeof ", @@ -3388,8 +3532,8 @@ "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" } ], "path": "packages/kbn-ftr-common-functional-services/services/all.ts", @@ -3484,13 +3628,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -3548,7 +3692,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -3680,13 +3840,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -3744,7 +3904,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -3943,13 +4119,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -4007,7 +4183,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -4139,13 +4331,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -4203,7 +4395,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -4372,7 +4580,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -4494,13 +4718,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -4558,7 +4782,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -4690,13 +4930,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -4754,7 +4994,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -4933,13 +5189,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -4997,7 +5253,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -5129,13 +5401,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -5193,7 +5465,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -5372,13 +5660,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -5436,7 +5724,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -5568,13 +5872,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -5632,7 +5936,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -5814,13 +6134,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -5878,7 +6198,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", @@ -6010,13 +6346,13 @@ "section": "def-common.RetryService", "text": "RetryService" }, - "; bsearch: typeof ", + "; search: typeof ", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", "docId": "kibKbnFtrCommonFunctionalServicesPluginApi", - "section": "def-common.BsearchService", - "text": "BsearchService" + "section": "def-common.SearchService", + "text": "SearchService" }, "; console: ({ getService }: ", { @@ -6074,7 +6410,23 @@ "section": "def-common.FtrProviderContext", "text": "FtrProviderContext" }, - ") => { getInteractiveUserSessionCookieWithRoleScope(role: string): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string): Promise<", + ") => { getInteractiveUserSessionCookieWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise; getM2MApiCookieCredentialsWithRoleScope(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined): Promise<", { "pluginId": "@kbn/ftr-common-functional-services", "scope": "common", diff --git a/api_docs/kbn_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index c100d6574538..a867f15a2ef9 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-06 +date: 2024-11-12 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 67bd8b0d5355..723193f3ff8c 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-06 +date: 2024-11-12 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 fa6d74b607f8..431e1754c3d8 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-06 +date: 2024-11-12 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 ec14481606c0..735ec74e591c 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-06 +date: 2024-11-12 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 27b350125d2a..993d1c37ed4f 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_grid_layout.mdx b/api_docs/kbn_grid_layout.mdx index a1b9c50dea62..57a3074656dc 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grid-layout'] --- import kbnGridLayoutObj from './kbn_grid_layout.devdocs.json'; diff --git a/api_docs/kbn_grouping.mdx b/api_docs/kbn_grouping.mdx index 60188a01a490..95cce0d41bab 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-06 +date: 2024-11-12 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 0a8993693dbc..567731d8779b 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-06 +date: 2024-11-12 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 484de7df2691..2124fcf4aed6 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-06 +date: 2024-11-12 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 4d976b1da447..320bed94d54a 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-06 +date: 2024-11-12 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 07377c5aa906..1d262d68de22 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-06 +date: 2024-11-12 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 670602973bd5..a706989eea5a 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-06 +date: 2024-11-12 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 385a3beb4218..26fe80f6e1c7 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-06 +date: 2024-11-12 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 043065c80ead..f4ce63cdc439 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-06 +date: 2024-11-12 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 8393a8de144e..8b7f563d8da9 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-06 +date: 2024-11-12 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 a80fa33dae80..c776e26e543b 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_index_lifecycle_management_common_shared.devdocs.json b/api_docs/kbn_index_lifecycle_management_common_shared.devdocs.json new file mode 100644 index 000000000000..62664293d6a4 --- /dev/null +++ b/api_docs/kbn_index_lifecycle_management_common_shared.devdocs.json @@ -0,0 +1,1447 @@ +{ + "id": "@kbn/index-lifecycle-management-common-shared", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.AllocateAction", + "type": "Interface", + "tags": [], + "label": "AllocateAction", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.AllocateAction.number_of_replicas", + "type": "number", + "tags": [], + "label": "number_of_replicas", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.AllocateAction.include", + "type": "Object", + "tags": [], + "label": "include", + "description": [], + "signature": [ + "{} | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.AllocateAction.exclude", + "type": "Object", + "tags": [], + "label": "exclude", + "description": [], + "signature": [ + "{} | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.AllocateAction.require", + "type": "Object", + "tags": [], + "label": "require", + "description": [], + "signature": [ + "{ [attribute: string]: string; } | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.CommonPhaseSettings", + "type": "Interface", + "tags": [], + "label": "CommonPhaseSettings", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.CommonPhaseSettings.phaseEnabled", + "type": "boolean", + "tags": [], + "label": "phaseEnabled", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.DeletePhase", + "type": "Interface", + "tags": [], + "label": "DeletePhase", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.DeletePhase", + "text": "DeletePhase" + }, + " extends ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.CommonPhaseSettings", + "text": "CommonPhaseSettings" + }, + ",", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.PhaseWithMinAge", + "text": "PhaseWithMinAge" + } + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.DeletePhase.waitForSnapshotPolicy", + "type": "string", + "tags": [], + "label": "waitForSnapshotPolicy", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.DownsampleAction", + "type": "Interface", + "tags": [], + "label": "DownsampleAction", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.DownsampleAction.fixed_interval", + "type": "string", + "tags": [], + "label": "fixed_interval", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.ForcemergeAction", + "type": "Interface", + "tags": [], + "label": "ForcemergeAction", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.ForcemergeAction.max_num_segments", + "type": "number", + "tags": [], + "label": "max_num_segments", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.ForcemergeAction.index_codec", + "type": "string", + "tags": [], + "label": "index_codec", + "description": [], + "signature": [ + "\"best_compression\" | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.MigrateAction", + "type": "Interface", + "tags": [], + "label": "MigrateAction", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.MigrateAction.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [ + "\nIf enabled is ever set it will probably only be set to `false` because the default value\nfor this is `true`. Rather leave unspecified for true when serialising." + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.Phases", + "type": "Interface", + "tags": [], + "label": "Phases", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.Phases.hot", + "type": "Object", + "tags": [], + "label": "hot", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedHotPhase", + "text": "SerializedHotPhase" + }, + " | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.Phases.warm", + "type": "Object", + "tags": [], + "label": "warm", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedWarmPhase", + "text": "SerializedWarmPhase" + }, + " | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.Phases.cold", + "type": "Object", + "tags": [], + "label": "cold", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedColdPhase", + "text": "SerializedColdPhase" + }, + " | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.Phases.frozen", + "type": "Object", + "tags": [], + "label": "frozen", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedFrozenPhase", + "text": "SerializedFrozenPhase" + }, + " | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.Phases.delete", + "type": "Object", + "tags": [], + "label": "delete", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedDeletePhase", + "text": "SerializedDeletePhase" + }, + " | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PhaseWithMinAge", + "type": "Interface", + "tags": [], + "label": "PhaseWithMinAge", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PhaseWithMinAge.selectedMinimumAge", + "type": "string", + "tags": [], + "label": "selectedMinimumAge", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PhaseWithMinAge.selectedMinimumAgeUnits", + "type": "string", + "tags": [], + "label": "selectedMinimumAgeUnits", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PolicyFromES", + "type": "Interface", + "tags": [], + "label": "PolicyFromES", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PolicyFromES.modifiedDate", + "type": "string", + "tags": [], + "label": "modifiedDate", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PolicyFromES.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PolicyFromES.policy", + "type": "Object", + "tags": [], + "label": "policy", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedPolicy", + "text": "SerializedPolicy" + } + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PolicyFromES.version", + "type": "number", + "tags": [], + "label": "version", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PolicyFromES.indices", + "type": "Array", + "tags": [], + "label": "indices", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PolicyFromES.dataStreams", + "type": "Array", + "tags": [], + "label": "dataStreams", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PolicyFromES.indexTemplates", + "type": "Array", + "tags": [], + "label": "indexTemplates", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.RolloverAction", + "type": "Interface", + "tags": [], + "label": "RolloverAction", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.RolloverAction.max_age", + "type": "string", + "tags": [], + "label": "max_age", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.RolloverAction.max_docs", + "type": "number", + "tags": [], + "label": "max_docs", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.RolloverAction.max_primary_shard_size", + "type": "string", + "tags": [], + "label": "max_primary_shard_size", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.RolloverAction.max_primary_shard_docs", + "type": "number", + "tags": [], + "label": "max_primary_shard_docs", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.RolloverAction.max_size", + "type": "string", + "tags": [ + "deprecated" + ], + "label": "max_size", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": true, + "trackAdoption": false, + "references": [ + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/__jest__/mocks.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/serializer/serializer.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/public/application/sections/policy_list/policy_flyout/components/rollover.tsx" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/public/application/sections/policy_list/policy_flyout/components/rollover.tsx" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/constants.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/constants.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/constants.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/integration_tests/edit_policy/constants.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer_and_serializer.test.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer_and_serializer.test.ts" + }, + { + "plugin": "indexLifecycleManagement", + "path": "x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/form/deserializer_and_serializer.test.ts" + } + ] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SearchableSnapshotAction", + "type": "Interface", + "tags": [], + "label": "SearchableSnapshotAction", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SearchableSnapshotAction.snapshot_repository", + "type": "string", + "tags": [], + "label": "snapshot_repository", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SearchableSnapshotAction.force_merge_index", + "type": "CompoundType", + "tags": [], + "label": "force_merge_index", + "description": [ + "\nWe do not configure this value in the UI as it is an advanced setting that will\nnot suit the vast majority of cases." + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedActionWithAllocation", + "type": "Interface", + "tags": [], + "label": "SerializedActionWithAllocation", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedActionWithAllocation.allocate", + "type": "Object", + "tags": [], + "label": "allocate", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.AllocateAction", + "text": "AllocateAction" + }, + " | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedActionWithAllocation.migrate", + "type": "Object", + "tags": [], + "label": "migrate", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.MigrateAction", + "text": "MigrateAction" + }, + " | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedColdPhase", + "type": "Interface", + "tags": [], + "label": "SerializedColdPhase", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedColdPhase", + "text": "SerializedColdPhase" + }, + " extends ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedPhase", + "text": "SerializedPhase" + } + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedColdPhase.actions", + "type": "Object", + "tags": [], + "label": "actions", + "description": [], + "signature": [ + "{ freeze?: {} | undefined; readonly?: {} | undefined; downsample?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.DownsampleAction", + "text": "DownsampleAction" + }, + " | undefined; allocate?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.AllocateAction", + "text": "AllocateAction" + }, + " | undefined; set_priority?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SetPriorityAction", + "text": "SetPriorityAction" + }, + " | undefined; migrate?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.MigrateAction", + "text": "MigrateAction" + }, + " | undefined; searchable_snapshot?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SearchableSnapshotAction", + "text": "SearchableSnapshotAction" + }, + " | undefined; }" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedDeletePhase", + "type": "Interface", + "tags": [], + "label": "SerializedDeletePhase", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedDeletePhase", + "text": "SerializedDeletePhase" + }, + " extends ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedPhase", + "text": "SerializedPhase" + } + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedDeletePhase.actions", + "type": "Object", + "tags": [], + "label": "actions", + "description": [], + "signature": [ + "{ wait_for_snapshot?: { policy: string; } | undefined; delete?: { delete_searchable_snapshot?: boolean | undefined; } | undefined; }" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedFrozenPhase", + "type": "Interface", + "tags": [], + "label": "SerializedFrozenPhase", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedFrozenPhase", + "text": "SerializedFrozenPhase" + }, + " extends ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedPhase", + "text": "SerializedPhase" + } + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedFrozenPhase.actions", + "type": "Object", + "tags": [], + "label": "actions", + "description": [], + "signature": [ + "{ searchable_snapshot?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SearchableSnapshotAction", + "text": "SearchableSnapshotAction" + }, + " | undefined; }" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedHotPhase", + "type": "Interface", + "tags": [], + "label": "SerializedHotPhase", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedHotPhase", + "text": "SerializedHotPhase" + }, + " extends ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedPhase", + "text": "SerializedPhase" + } + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedHotPhase.actions", + "type": "Object", + "tags": [], + "label": "actions", + "description": [], + "signature": [ + "{ rollover?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.RolloverAction", + "text": "RolloverAction" + }, + " | undefined; forcemerge?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.ForcemergeAction", + "text": "ForcemergeAction" + }, + " | undefined; readonly?: {} | undefined; shrink?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.ShrinkAction", + "text": "ShrinkAction" + }, + " | undefined; downsample?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.DownsampleAction", + "text": "DownsampleAction" + }, + " | undefined; set_priority?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SetPriorityAction", + "text": "SetPriorityAction" + }, + " | undefined; searchable_snapshot?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SearchableSnapshotAction", + "text": "SearchableSnapshotAction" + }, + " | undefined; }" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedPhase", + "type": "Interface", + "tags": [], + "label": "SerializedPhase", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedPhase.min_age", + "type": "string", + "tags": [], + "label": "min_age", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedPhase.actions", + "type": "Object", + "tags": [], + "label": "actions", + "description": [], + "signature": [ + "{ [action: string]: any; }" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedPolicy", + "type": "Interface", + "tags": [], + "label": "SerializedPolicy", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedPolicy.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedPolicy.phases", + "type": "Object", + "tags": [], + "label": "phases", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.Phases", + "text": "Phases" + } + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedPolicy.deprecated", + "type": "CompoundType", + "tags": [], + "label": "deprecated", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedPolicy._meta", + "type": "Object", + "tags": [], + "label": "_meta", + "description": [], + "signature": [ + "Record | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedWarmPhase", + "type": "Interface", + "tags": [], + "label": "SerializedWarmPhase", + "description": [], + "signature": [ + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedWarmPhase", + "text": "SerializedWarmPhase" + }, + " extends ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SerializedPhase", + "text": "SerializedPhase" + } + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SerializedWarmPhase.actions", + "type": "Object", + "tags": [], + "label": "actions", + "description": [], + "signature": [ + "{ allocate?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.AllocateAction", + "text": "AllocateAction" + }, + " | undefined; shrink?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.ShrinkAction", + "text": "ShrinkAction" + }, + " | undefined; forcemerge?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.ForcemergeAction", + "text": "ForcemergeAction" + }, + " | undefined; readonly?: {} | undefined; downsample?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.DownsampleAction", + "text": "DownsampleAction" + }, + " | undefined; set_priority?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.SetPriorityAction", + "text": "SetPriorityAction" + }, + " | undefined; migrate?: ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.MigrateAction", + "text": "MigrateAction" + }, + " | undefined; }" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SetPriorityAction", + "type": "Interface", + "tags": [], + "label": "SetPriorityAction", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.SetPriorityAction.priority", + "type": "CompoundType", + "tags": [], + "label": "priority", + "description": [], + "signature": [ + "number | null" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.ShrinkAction", + "type": "Interface", + "tags": [], + "label": "ShrinkAction", + "description": [], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.ShrinkAction.number_of_shards", + "type": "number", + "tags": [], + "label": "number_of_shards", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.ShrinkAction.max_primary_shard_size", + "type": "string", + "tags": [], + "label": "max_primary_shard_size", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.ShrinkAction.allow_write_after_shrink", + "type": "CompoundType", + "tags": [], + "label": "allow_write_after_shrink", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.ILM_LOCATOR_ID", + "type": "string", + "tags": [], + "label": "ILM_LOCATOR_ID", + "description": [], + "signature": [ + "\"ILM_LOCATOR_ID\"" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.Phase", + "type": "Type", + "tags": [], + "label": "Phase", + "description": [], + "signature": [ + "keyof ", + { + "pluginId": "@kbn/index-lifecycle-management-common-shared", + "scope": "common", + "docId": "kibKbnIndexLifecycleManagementCommonSharedPluginApi", + "section": "def-common.Phases", + "text": "Phases" + } + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PhaseExceptDelete", + "type": "Type", + "tags": [], + "label": "PhaseExceptDelete", + "description": [], + "signature": [ + "\"warm\" | \"hot\" | \"frozen\" | \"cold\"" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PhaseWithAllocation", + "type": "Type", + "tags": [], + "label": "PhaseWithAllocation", + "description": [], + "signature": [ + "\"warm\" | \"cold\"" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PhaseWithDownsample", + "type": "Type", + "tags": [], + "label": "PhaseWithDownsample", + "description": [], + "signature": [ + "\"warm\" | \"hot\" | \"cold\"" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/index-lifecycle-management-common-shared", + "id": "def-common.PhaseWithTiming", + "type": "Type", + "tags": [], + "label": "PhaseWithTiming", + "description": [], + "signature": [ + "\"delete\" | \"warm\" | \"frozen\" | \"cold\"" + ], + "path": "x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_index_lifecycle_management_common_shared.mdx b/api_docs/kbn_index_lifecycle_management_common_shared.mdx new file mode 100644 index 000000000000..0ed700c24a6e --- /dev/null +++ b/api_docs/kbn_index_lifecycle_management_common_shared.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: kibKbnIndexLifecycleManagementCommonSharedPluginApi +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-12 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/index-lifecycle-management-common-shared'] +--- +import kbnIndexLifecycleManagementCommonSharedObj from './kbn_index_lifecycle_management_common_shared.devdocs.json'; + + + +Contact [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 75 | 0 | 73 | 0 | + +## Common + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_index_management_shared_types.mdx b/api_docs/kbn_index_management_shared_types.mdx index 21c63e7d7c18..8c28979c41e4 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-06 +date: 2024-11-12 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 138e699222ac..8724d9451e1d 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-06 +date: 2024-11-12 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 d57fe4e6254f..a8e658592606 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-06 +date: 2024-11-12 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 898eeb2298a7..ff578001a59f 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-06 +date: 2024-11-12 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 6a03c64a0994..7a1f6e64c175 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-06 +date: 2024-11-12 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 c03ed5cdafb7..a1dd7ecaaf2b 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-06 +date: 2024-11-12 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 c4436311efcb..a104f3097eff 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-06 +date: 2024-11-12 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 675e76db1a44..2b496ce99a8a 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-06 +date: 2024-11-12 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 45669c406eed..38d654ba2bb8 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-06 +date: 2024-11-12 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 d1410ef30cff..c2fec834962d 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-06 +date: 2024-11-12 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 207f52bed418..d213ff07e87f 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-06 +date: 2024-11-12 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 2cdb8dbf8e1a..3fe23883d8cb 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-06 +date: 2024-11-12 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 a87c702eb903..3a94e136d53e 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-06 +date: 2024-11-12 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.devdocs.json b/api_docs/kbn_kibana_manifest_schema.devdocs.json index 296e6527f7bc..a5cfad840992 100644 --- a/api_docs/kbn_kibana_manifest_schema.devdocs.json +++ b/api_docs/kbn_kibana_manifest_schema.devdocs.json @@ -1024,66 +1024,6 @@ "path": "packages/kbn-kibana-manifest-schema/src/kibana_json_v2_schema.ts", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "@kbn/kibana-manifest-schema", - "id": "def-common.MANIFEST_V2.properties.group.default", - "type": "string", - "tags": [], - "label": "default", - "description": [], - "path": "packages/kbn-kibana-manifest-schema/src/kibana_json_v2_schema.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, - { - "parentPluginId": "@kbn/kibana-manifest-schema", - "id": "def-common.MANIFEST_V2.properties.visibility", - "type": "Object", - "tags": [], - "label": "visibility", - "description": [], - "path": "packages/kbn-kibana-manifest-schema/src/kibana_json_v2_schema.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/kibana-manifest-schema", - "id": "def-common.MANIFEST_V2.properties.visibility.enum", - "type": "Array", - "tags": [], - "label": "enum", - "description": [], - "signature": [ - "string[]" - ], - "path": "packages/kbn-kibana-manifest-schema/src/kibana_json_v2_schema.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/kibana-manifest-schema", - "id": "def-common.MANIFEST_V2.properties.visibility.description", - "type": "string", - "tags": [], - "label": "description", - "description": [], - "path": "packages/kbn-kibana-manifest-schema/src/kibana_json_v2_schema.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/kibana-manifest-schema", - "id": "def-common.MANIFEST_V2.properties.visibility.default", - "type": "string", - "tags": [], - "label": "default", - "description": [], - "path": "packages/kbn-kibana-manifest-schema/src/kibana_json_v2_schema.ts", - "deprecated": false, - "trackAdoption": false } ] }, @@ -1398,6 +1338,20 @@ } ] }, + { + "parentPluginId": "@kbn/kibana-manifest-schema", + "id": "def-common.MANIFEST_V2.allOf", + "type": "Array", + "tags": [], + "label": "allOf", + "description": [], + "signature": [ + "{ if: { properties: { group: { const: string; }; }; }; then: { properties: { visibility: { enum: string[]; description: string; default: string; }; }; required: string[]; }; else: { properties: { visibility: { const: string; description: string; default: string; }; }; required: string[]; }; }[]" + ], + "path": "packages/kbn-kibana-manifest-schema/src/kibana_json_v2_schema.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/kibana-manifest-schema", "id": "def-common.MANIFEST_V2.oneOf", diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 69512eb9fa3d..9d4377358e12 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 116 | 0 | 115 | 0 | +| 112 | 0 | 111 | 0 | ## Common diff --git a/api_docs/kbn_language_documentation.mdx b/api_docs/kbn_language_documentation.mdx index 89f31cc1b7d5..85764d5c9825 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-06 +date: 2024-11-12 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 1ac19ac1a8fc..535c118c9dec 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-06 +date: 2024-11-12 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 5ecc1c889d35..106924491873 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-06 +date: 2024-11-12 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 f5a4b6d3c6bd..c3154b703fed 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-06 +date: 2024-11-12 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 87e4efb1bf65..e6be28e24ce4 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-06 +date: 2024-11-12 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 285dae6be64f..2e6ffa89d004 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-06 +date: 2024-11-12 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 098e7e428030..f152444c1f62 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-06 +date: 2024-11-12 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 b63b44202755..69e712b46815 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-06 +date: 2024-11-12 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 0e2ba5036555..16e99fc5cc94 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-06 +date: 2024-11-12 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 560399c823fd..a00641e9efbc 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-06 +date: 2024-11-12 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 251dc221a67c..b071cbc09693 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-06 +date: 2024-11-12 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 9cfe45be0d4a..f79d711ca521 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-06 +date: 2024-11-12 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 b40c4c5d9f38..de54101e88d0 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-06 +date: 2024-11-12 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 29105b893375..940d0042bfc8 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-06 +date: 2024-11-12 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.devdocs.json b/api_docs/kbn_management_settings_ids.devdocs.json index 19accbeb0d25..bc654d267378 100644 --- a/api_docs/kbn_management_settings_ids.devdocs.json +++ b/api_docs/kbn_management_settings_ids.devdocs.json @@ -907,21 +907,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/management-settings-ids", - "id": "def-common.METRICS_ALLOW_CHECKING_FOR_FAILED_SHARDS_ID", - "type": "string", - "tags": [], - "label": "METRICS_ALLOW_CHECKING_FOR_FAILED_SHARDS_ID", - "description": [], - "signature": [ - "\"metrics:allowCheckingForFailedShards\"" - ], - "path": "packages/kbn-management/settings/setting_ids/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/management-settings-ids", "id": "def-common.METRICS_ALLOW_STRING_INDICES_ID", diff --git a/api_docs/kbn_management_settings_ids.mdx b/api_docs/kbn_management_settings_ids.mdx index 43461c5db868..0a46cd757128 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-ids'] --- import kbnManagementSettingsIdsObj from './kbn_management_settings_ids.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 140 | 0 | 139 | 0 | +| 139 | 0 | 138 | 0 | ## Common diff --git a/api_docs/kbn_management_settings_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index 148b9557c619..c4dba23025fd 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-06 +date: 2024-11-12 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 79c1c6a5f577..b52d09baa28e 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-06 +date: 2024-11-12 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 cffd209cfc34..03d44b182880 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-06 +date: 2024-11-12 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 0ac3ec7f8c11..a001d12638f0 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-06 +date: 2024-11-12 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 0b0b58e81140..8fd4aea6ac22 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-06 +date: 2024-11-12 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 add5bcd0ac11..b0b5c6273ea9 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-06 +date: 2024-11-12 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 1e1ac5158592..2cc52ca631c6 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-06 +date: 2024-11-12 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 76dbf659ab6f..7dcf7843651c 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-06 +date: 2024-11-12 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 e9d5ab5151d1..49bcc89d3d99 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-06 +date: 2024-11-12 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 d360785b7711..a4d9b5a984f3 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-06 +date: 2024-11-12 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 698608d6a553..a79a0aeaf53e 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-06 +date: 2024-11-12 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 49e071f62828..ff3a6ba6c48a 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-06 +date: 2024-11-12 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 8c9067580760..4c3f4b54e464 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-06 +date: 2024-11-12 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 9e9805b03a1d..fddb315a8919 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-06 +date: 2024-11-12 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 d9047f8d307b..dbb7cc6c40cc 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-06 +date: 2024-11-12 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 3bf163268482..7d6c510e3420 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-06 +date: 2024-11-12 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 b9ce7b69dc6b..14cfe80893ad 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-06 +date: 2024-11-12 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 a5bd542b665d..7d5b991fac89 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-06 +date: 2024-11-12 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 4aad4c3840f4..adf618a7bc18 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-06 +date: 2024-11-12 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 f755ae87515b..b9a5f9259d43 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-06 +date: 2024-11-12 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 b9ec6e725588..88020badbad1 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-06 +date: 2024-11-12 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 5891c6100ed0..db9949aeef20 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-06 +date: 2024-11-12 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 b52d9abc106a..4986f6e22610 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-06 +date: 2024-11-12 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 edd6b0c94c1a..7bebcbd38965 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-06 +date: 2024-11-12 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 f32d9ab1a906..ffc7decec804 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-06 +date: 2024-11-12 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 5971eda11bb4..5c276242db36 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-06 +date: 2024-11-12 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 4ae1ff638d2a..9a1bab0cc2bb 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-06 +date: 2024-11-12 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 abd5808a292c..aafa96694cab 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-06 +date: 2024-11-12 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 3f119fa3cb06..b07f25d73fce 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-06 +date: 2024-11-12 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 1c02d86192f9..63076aa68f7e 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-06 +date: 2024-11-12 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 152dc97d3823..596110c69468 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-06 +date: 2024-11-12 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 99edea504de5..77d3e0cdb27d 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-06 +date: 2024-11-12 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 2097abba01e1..60724e72677b 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-06 +date: 2024-11-12 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 05da7971e3f1..343401b698cf 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-06 +date: 2024-11-12 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 1d7dce7bab50..6df0063365e7 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-06 +date: 2024-11-12 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 10becee027ce..23e597e2f0f4 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-06 +date: 2024-11-12 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 84b8ae23e76a..742d202cbcee 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-06 +date: 2024-11-12 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 8f09a70d05d1..a96e583d94e9 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-06 +date: 2024-11-12 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 c7384fa4982b..1defebd09d22 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-06 +date: 2024-11-12 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 457f21c17346..8a81cb4f518a 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-06 +date: 2024-11-12 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 3d59ec1e25b1..24b2d0f27bbd 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-06 +date: 2024-11-12 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 98cf4dcd91b6..c6067a685e93 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-06 +date: 2024-11-12 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 ad12355b3826..5ad4d6d3f360 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-06 +date: 2024-11-12 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 40b1a8c5b674..d8207d81dc26 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-06 +date: 2024-11-12 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.mdx b/api_docs/kbn_observability_logs_overview.mdx index 7a5cba802204..58a812061ea3 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-logs-overview'] --- import kbnObservabilityLogsOverviewObj from './kbn_observability_logs_overview.devdocs.json'; diff --git a/api_docs/kbn_observability_synthetics_test_data.mdx b/api_docs/kbn_observability_synthetics_test_data.mdx index 6e5c5af77d6f..b10096eabf86 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-06 +date: 2024-11-12 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 70e22d810db2..e24dad4ac4c3 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-06 +date: 2024-11-12 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 a3db1df4c164..bdb4b573a9f8 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-06 +date: 2024-11-12 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 7c79bc4e5a62..928955cf42b7 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-06 +date: 2024-11-12 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 da1d105f9e58..b973e2fc2870 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-06 +date: 2024-11-12 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 44f61726ce68..b365a12c78ac 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-06 +date: 2024-11-12 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 1bd3f7898f84..e762e0372171 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-06 +date: 2024-11-12 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 365f9bce8bd8..3165245e2fb9 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-06 +date: 2024-11-12 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 a79f5c38b46a..0ad957cfc519 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-06 +date: 2024-11-12 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 8cc84dfa82b4..996544ca5019 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-06 +date: 2024-11-12 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 1e3fc71268a6..a338af0b3786 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-06 +date: 2024-11-12 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 60d27e1cdca5..35c491dd3aa3 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-containers'] --- import kbnPresentationContainersObj from './kbn_presentation_containers.devdocs.json'; diff --git a/api_docs/kbn_presentation_publishing.mdx b/api_docs/kbn_presentation_publishing.mdx index c9d286d7daec..ea63d73b7320 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-publishing'] --- import kbnPresentationPublishingObj from './kbn_presentation_publishing.devdocs.json'; diff --git a/api_docs/kbn_product_doc_artifact_builder.mdx b/api_docs/kbn_product_doc_artifact_builder.mdx index 17d04b89d744..e737c606ba67 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-06 +date: 2024-11-12 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_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index 929a683eb45c..2461ac60f5b9 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-06 +date: 2024-11-12 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 c8396ed6a659..278a1b53b11e 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-06 +date: 2024-11-12 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 18e1f7946700..6cc9939a14c1 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-06 +date: 2024-11-12 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 81b591870daa..d0a86fc48bda 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-06 +date: 2024-11-12 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 6f5072997d84..fafac45b43fa 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-06 +date: 2024-11-12 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 8e03bbf9ac8e..268d249666ad 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-06 +date: 2024-11-12 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 dabab5b20e19..89408f64335a 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-06 +date: 2024-11-12 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 227743a3adbe..642c0f510d32 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-06 +date: 2024-11-12 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 f64c3f2df048..6d69b3e1feb5 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-06 +date: 2024-11-12 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 43dec8a304a6..23d49b1d84a8 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-06 +date: 2024-11-12 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 3d099844ed38..fb70861bf5c8 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-06 +date: 2024-11-12 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 6ead7a0093ab..c3e6209fe0cb 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-06 +date: 2024-11-12 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 c66b9d770035..0a344992f367 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-06 +date: 2024-11-12 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 d6ab42221ced..d4593bb69ec1 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-06 +date: 2024-11-12 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 27eb86ac7cf5..4bc026939319 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-06 +date: 2024-11-12 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.devdocs.json b/api_docs/kbn_reporting_common.devdocs.json index b7b20c613c82..be3dfff0ff7f 100644 --- a/api_docs/kbn_reporting_common.devdocs.json +++ b/api_docs/kbn_reporting_common.devdocs.json @@ -1551,17 +1551,6 @@ } ] }, - { - "parentPluginId": "@kbn/reporting-common", - "id": "def-common.INTERNAL_ROUTES.DOWNLOAD_CSV", - "type": "string", - "tags": [], - "label": "DOWNLOAD_CSV", - "description": [], - "path": "packages/kbn-reporting/common/routes.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "@kbn/reporting-common", "id": "def-common.INTERNAL_ROUTES.GENERATE_PREFIX", diff --git a/api_docs/kbn_reporting_common.mdx b/api_docs/kbn_reporting_common.mdx index 2d427ce35c66..495a620eed08 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 99 | 0 | 89 | 13 | +| 98 | 0 | 88 | 13 | ## Common diff --git a/api_docs/kbn_reporting_csv_share_panel.mdx b/api_docs/kbn_reporting_csv_share_panel.mdx index afed2c3ec063..fcdbcff99440 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-06 +date: 2024-11-12 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.devdocs.json b/api_docs/kbn_reporting_export_types_csv.devdocs.json index 7d14ab99bddb..cab900fc5f38 100644 --- a/api_docs/kbn_reporting_export_types_csv.devdocs.json +++ b/api_docs/kbn_reporting_export_types_csv.devdocs.json @@ -405,358 +405,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType", - "type": "Class", - "tags": [ - "deprecated" - ], - "label": "CsvSearchSourceImmediateExportType", - "description": [], - "signature": [ - { - "pluginId": "@kbn/reporting-export-types-csv", - "scope": "server", - "docId": "kibKbnReportingExportTypesCsvPluginApi", - "section": "def-server.CsvSearchSourceImmediateExportType", - "text": "CsvSearchSourceImmediateExportType" - }, - " extends ", - { - "pluginId": "@kbn/reporting-server", - "scope": "server", - "docId": "kibKbnReportingServerPluginApi", - "section": "def-server.ExportType", - "text": "ExportType" - }, - "<", - { - "pluginId": "@kbn/reporting-export-types-csv-common", - "scope": "common", - "docId": "kibKbnReportingExportTypesCsvCommonPluginApi", - "section": "def-common.JobParamsDownloadCSV", - "text": "JobParamsDownloadCSV" - }, - ", ", - "ImmediateExecuteFn", - ", ", - { - "pluginId": "@kbn/reporting-server", - "scope": "server", - "docId": "kibKbnReportingServerPluginApi", - "section": "def-server.BaseExportTypeSetupDeps", - "text": "BaseExportTypeSetupDeps" - }, - ", CsvSearchSourceImmediateExportTypeStartDeps>" - ], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": true, - "trackAdoption": false, - "references": [ - { - "plugin": "reporting", - "path": "x-pack/plugins/reporting/server/core.ts" - }, - { - "plugin": "reporting", - "path": "x-pack/plugins/reporting/server/core.ts" - } - ], - "children": [ - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.id", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.name", - "type": "string", - "tags": [], - "label": "name", - "description": [], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.jobType", - "type": "string", - "tags": [], - "label": "jobType", - "description": [], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.jobContentEncoding", - "type": "string", - "tags": [], - "label": "jobContentEncoding", - "description": [], - "signature": [ - "\"base64\"" - ], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.jobContentExtension", - "type": "string", - "tags": [], - "label": "jobContentExtension", - "description": [], - "signature": [ - "\"csv\"" - ], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.validLicenses", - "type": "Array", - "tags": [], - "label": "validLicenses", - "description": [], - "signature": [ - "(\"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\")[]" - ], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.Unnamed", - "type": "Function", - "tags": [], - "label": "Constructor", - "description": [], - "signature": [ - "any" - ], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.Unnamed.$1", - "type": "Object", - "tags": [], - "label": "args", - "description": [], - "signature": [ - "[core: ", - { - "pluginId": "@kbn/core-lifecycle-server", - "scope": "server", - "docId": "kibKbnCoreLifecycleServerPluginApi", - "section": "def-server.CoreSetup", - "text": "CoreSetup" - }, - ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{} & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", - { - "pluginId": "@kbn/config-schema", - "scope": "common", - "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.ByteSizeValue", - "text": "ByteSizeValue" - }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>, logger: ", - { - "pluginId": "@kbn/logging", - "scope": "common", - "docId": "kibKbnLoggingPluginApi", - "section": "def-common.Logger", - "text": "Logger" - }, - ", context: ", - { - "pluginId": "@kbn/core-plugins-server", - "scope": "server", - "docId": "kibKbnCorePluginsServerPluginApi", - "section": "def-server.PluginInitializerContext", - "text": "PluginInitializerContext" - }, - "; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", - { - "pluginId": "@kbn/config-schema", - "scope": "common", - "docId": "kibKbnConfigSchemaPluginApi", - "section": "def-common.ByteSizeValue", - "text": "ByteSizeValue" - }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>]" - ], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.createJob", - "type": "Function", - "tags": [], - "label": "createJob", - "description": [], - "signature": [ - "() => Promise" - ], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.runTask", - "type": "Function", - "tags": [], - "label": "runTask", - "description": [], - "signature": [ - "(_jobId: string | null, immediateJobParams: ", - { - "pluginId": "@kbn/reporting-export-types-csv-common", - "scope": "common", - "docId": "kibKbnReportingExportTypesCsvCommonPluginApi", - "section": "def-common.JobParamsDownloadCSV", - "text": "JobParamsDownloadCSV" - }, - ", context: ", - "ReportingRequestHandlerContext", - ", stream: ", - "Writable", - ", req: ", - { - "pluginId": "@kbn/core-http-server", - "scope": "server", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.KibanaRequest", - "text": "KibanaRequest" - }, - ") => Promise<", - "TaskRunResult", - ">" - ], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.runTask.$1", - "type": "CompoundType", - "tags": [], - "label": "_jobId", - "description": [], - "signature": [ - "string | null" - ], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.runTask.$2", - "type": "Object", - "tags": [], - "label": "immediateJobParams", - "description": [], - "signature": [ - { - "pluginId": "@kbn/reporting-export-types-csv-common", - "scope": "common", - "docId": "kibKbnReportingExportTypesCsvCommonPluginApi", - "section": "def-common.JobParamsDownloadCSV", - "text": "JobParamsDownloadCSV" - } - ], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.runTask.$3", - "type": "CompoundType", - "tags": [], - "label": "context", - "description": [], - "signature": [ - "ReportingRequestHandlerContext" - ], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.runTask.$4", - "type": "Object", - "tags": [], - "label": "stream", - "description": [], - "signature": [ - "Writable" - ], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv", - "id": "def-server.CsvSearchSourceImmediateExportType.runTask.$5", - "type": "Object", - "tags": [], - "label": "req", - "description": [], - "signature": [ - { - "pluginId": "@kbn/core-http-server", - "scope": "server", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.KibanaRequest", - "text": "KibanaRequest" - }, - "" - ], - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - } - ], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/reporting-export-types-csv", "id": "def-server.CsvV2ExportType", diff --git a/api_docs/kbn_reporting_export_types_csv.mdx b/api_docs/kbn_reporting_export_types_csv.mdx index 501d9c836b8c..bd9f21e11dc5 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv'] --- import kbnReportingExportTypesCsvObj from './kbn_reporting_export_types_csv.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 52 | 0 | 52 | 3 | +| 36 | 0 | 36 | 2 | ## Server diff --git a/api_docs/kbn_reporting_export_types_csv_common.devdocs.json b/api_docs/kbn_reporting_export_types_csv_common.devdocs.json index 32f5cd9dda2f..291e445f24f4 100644 --- a/api_docs/kbn_reporting_export_types_csv_common.devdocs.json +++ b/api_docs/kbn_reporting_export_types_csv_common.devdocs.json @@ -107,176 +107,6 @@ } ], "interfaces": [ - { - "parentPluginId": "@kbn/reporting-export-types-csv-common", - "id": "def-common.JobParamsDownloadCSV", - "type": "Interface", - "tags": [ - "deprecated" - ], - "label": "JobParamsDownloadCSV", - "description": [], - "path": "packages/kbn-reporting/export_types/csv_common/index.ts", - "deprecated": true, - "trackAdoption": false, - "references": [ - { - "plugin": "@kbn/reporting-export-types-csv", - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts" - }, - { - "plugin": "@kbn/reporting-export-types-csv", - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts" - }, - { - "plugin": "@kbn/reporting-export-types-csv", - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts" - }, - { - "plugin": "@kbn/reporting-export-types-csv", - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts" - }, - { - "plugin": "reporting", - "path": "x-pack/plugins/reporting/server/routes/internal/generate/csv_searchsource_immediate.ts" - }, - { - "plugin": "reporting", - "path": "x-pack/plugins/reporting/server/routes/internal/generate/csv_searchsource_immediate.ts" - } - ], - "children": [ - { - "parentPluginId": "@kbn/reporting-export-types-csv-common", - "id": "def-common.JobParamsDownloadCSV.browserTimezone", - "type": "string", - "tags": [], - "label": "browserTimezone", - "description": [], - "path": "packages/kbn-reporting/export_types/csv_common/index.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv-common", - "id": "def-common.JobParamsDownloadCSV.title", - "type": "string", - "tags": [], - "label": "title", - "description": [], - "path": "packages/kbn-reporting/export_types/csv_common/index.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv-common", - "id": "def-common.JobParamsDownloadCSV.searchSource", - "type": "Object", - "tags": [], - "label": "searchSource", - "description": [], - "signature": [ - "{ type?: string | undefined; query?: ", - { - "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; filter?: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Filter", - "text": "Filter" - }, - "[] | undefined; sort?: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.EsQuerySortValue", - "text": "EsQuerySortValue" - }, - "[] | undefined; highlight?: ", - { - "pluginId": "@kbn/utility-types", - "scope": "common", - "docId": "kibKbnUtilityTypesPluginApi", - "section": "def-common.SerializableRecord", - "text": "SerializableRecord" - }, - " | undefined; highlightAll?: boolean | undefined; trackTotalHits?: number | boolean | undefined; aggs?: { type: string; enabled?: boolean | undefined; id?: string | undefined; params?: {} | ", - { - "pluginId": "@kbn/utility-types", - "scope": "common", - "docId": "kibKbnUtilityTypesPluginApi", - "section": "def-common.SerializableRecord", - "text": "SerializableRecord" - }, - " | undefined; schema?: string | undefined; }[] | undefined; from?: number | undefined; size?: number | undefined; source?: boolean | ", - "Fields", - " | undefined; version?: boolean | undefined; fields?: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchFieldValue", - "text": "SearchFieldValue" - }, - "[] | undefined; fieldsFromSource?: ", - "Fields", - " | undefined; index?: string | ", - { - "pluginId": "dataViews", - "scope": "common", - "docId": "kibDataViewsPluginApi", - "section": "def-common.DataViewSpec", - "text": "DataViewSpec" - }, - " | undefined; searchAfter?: ", - "SortResults", - " | undefined; timeout?: string | undefined; terminate_after?: number | undefined; parent?: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SerializedSearchSourceFields", - "text": "SerializedSearchSourceFields" - }, - " | undefined; }" - ], - "path": "packages/kbn-reporting/export_types/csv_common/index.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/reporting-export-types-csv-common", - "id": "def-common.JobParamsDownloadCSV.columns", - "type": "Array", - "tags": [], - "label": "columns", - "description": [], - "signature": [ - "string[] | undefined" - ], - "path": "packages/kbn-reporting/export_types/csv_common/index.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/reporting-export-types-csv-common", "id": "def-common.QueryInspection", @@ -465,53 +295,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/reporting-export-types-csv-common", - "id": "def-common.CSV_SEARCHSOURCE_IMMEDIATE_TYPE", - "type": "string", - "tags": [ - "deprecated" - ], - "label": "CSV_SEARCHSOURCE_IMMEDIATE_TYPE", - "description": [], - "signature": [ - "\"csv_searchsource_immediate\"" - ], - "path": "packages/kbn-reporting/export_types/csv_common/index.ts", - "deprecated": true, - "trackAdoption": false, - "references": [ - { - "plugin": "@kbn/reporting-export-types-csv", - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts" - }, - { - "plugin": "@kbn/reporting-export-types-csv", - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts" - }, - { - "plugin": "@kbn/reporting-export-types-csv", - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts" - }, - { - "plugin": "@kbn/reporting-export-types-csv", - "path": "packages/kbn-reporting/export_types/csv/csv_searchsource_immediate.ts" - }, - { - "plugin": "reporting", - "path": "x-pack/plugins/reporting/server/routes/internal/generate/csv_searchsource_immediate.ts" - }, - { - "plugin": "reporting", - "path": "x-pack/plugins/reporting/server/routes/internal/generate/csv_searchsource_immediate.ts" - }, - { - "plugin": "reporting", - "path": "x-pack/plugins/reporting/server/routes/internal/generate/csv_searchsource_immediate.ts" - } - ], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/reporting-export-types-csv-common", "id": "def-common.JobAppParamsCSV", @@ -522,7 +305,15 @@ "\nPublic-facing interface\nApps should use this interface to build job params. The browserTimezone and version\nfields become automatically provided by Reporting" ], "signature": [ - "{ title: string; columns?: string[] | undefined; layout?: { id?: ", + "{ title: string; columns?: string[] | undefined; searchSource: ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SerializedSearchSourceFields", + "text": "SerializedSearchSourceFields" + }, + "; layout?: { id?: ", { "pluginId": "screenshotting", "scope": "common", @@ -532,15 +323,7 @@ }, " | undefined; dimensions?: { width: number; height: number; } | undefined; selectors?: Partial<", "LayoutSelectorDictionary", - "> | undefined; zoom?: number | undefined; } | undefined; objectType: string; searchSource: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SerializedSearchSourceFields", - "text": "SerializedSearchSourceFields" - }, - "; pagingStrategy?: ", + "> | undefined; zoom?: number | undefined; } | undefined; objectType: string; pagingStrategy?: ", "CsvPagingStrategy", " | undefined; }" ], diff --git a/api_docs/kbn_reporting_export_types_csv_common.mdx b/api_docs/kbn_reporting_export_types_csv_common.mdx index a7dc6b1e2aa2..a733ea5344aa 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv-common'] --- import kbnReportingExportTypesCsvCommonObj from './kbn_reporting_export_types_csv_common.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 25 | 0 | 21 | 0 | +| 19 | 0 | 15 | 0 | ## Common diff --git a/api_docs/kbn_reporting_export_types_pdf.mdx b/api_docs/kbn_reporting_export_types_pdf.mdx index 3ce91456ca21..1511dd22eeb3 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-06 +date: 2024-11-12 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 772f39d99cdb..bff1a6c5a298 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-06 +date: 2024-11-12 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 56ca2c5d70d4..d9948ebfb004 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-06 +date: 2024-11-12 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 cba69558b29a..cc2af3e7afe0 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-06 +date: 2024-11-12 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 79b597027452..823e66dde25c 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-06 +date: 2024-11-12 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.devdocs.json b/api_docs/kbn_reporting_public.devdocs.json index 53e89b4395ac..a57898a72dd7 100644 --- a/api_docs/kbn_reporting_public.devdocs.json +++ b/api_docs/kbn_reporting_public.devdocs.json @@ -1310,60 +1310,6 @@ ], "returnComment": [] }, - { - "parentPluginId": "@kbn/reporting-public", - "id": "def-public.ReportingAPIClient.createImmediateReport", - "type": "Function", - "tags": [ - "deprecated" - ], - "label": "createImmediateReport", - "description": [], - "signature": [ - "(baseParams: ", - "BaseParams", - ") => Promise<", - { - "pluginId": "@kbn/core-http-browser", - "scope": "public", - "docId": "kibKbnCoreHttpBrowserPluginApi", - "section": "def-public.HttpResponse", - "text": "HttpResponse" - }, - ">" - ], - "path": "packages/kbn-reporting/public/reporting_api_client.ts", - "deprecated": true, - "trackAdoption": false, - "references": [ - { - "plugin": "@kbn/reporting-csv-share-panel", - "path": "packages/kbn-reporting/get_csv_panel_actions/panel_actions/get_csv_panel_action.tsx" - }, - { - "plugin": "@kbn/reporting-csv-share-panel", - "path": "packages/kbn-reporting/get_csv_panel_actions/panel_actions/get_csv_panel_action.test.ts" - } - ], - "children": [ - { - "parentPluginId": "@kbn/reporting-public", - "id": "def-public.ReportingAPIClient.createImmediateReport.$1", - "type": "Object", - "tags": [], - "label": "baseParams", - "description": [], - "signature": [ - "BaseParams" - ], - "path": "packages/kbn-reporting/public/reporting_api_client.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, { "parentPluginId": "@kbn/reporting-public", "id": "def-public.ReportingAPIClient.getDecoratedJobParams", @@ -1744,7 +1690,7 @@ "label": "csv", "description": [], "signature": [ - "{ enablePanelActionDownload: boolean; scroll: { duration: string; size: number; }; }" + "{ scroll: { duration: string; size: number; }; }" ], "path": "packages/kbn-reporting/public/types.ts", "deprecated": false, diff --git a/api_docs/kbn_reporting_public.mdx b/api_docs/kbn_reporting_public.mdx index 35cac1de1810..adb3de1a0cdc 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-public'] --- import kbnReportingPublicObj from './kbn_reporting_public.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 113 | 0 | 106 | 2 | +| 111 | 0 | 104 | 2 | ## Client diff --git a/api_docs/kbn_reporting_server.mdx b/api_docs/kbn_reporting_server.mdx index 100467e07247..18dfc6adf3e4 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-06 +date: 2024-11-12 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 1a061e65688c..d6fcf1550c50 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-06 +date: 2024-11-12 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 acc27f1c6138..b22e6a15fe0e 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-06 +date: 2024-11-12 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 6d8e579f12ba..4d2c8f2bf282 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-06 +date: 2024-11-12 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 8651aad062b1..a3f6b6cc34cc 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-06 +date: 2024-11-12 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 e0f9449525a6..f5b6092d2557 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-06 +date: 2024-11-12 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 abd3858f4002..fe7d8a3d6799 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-06 +date: 2024-11-12 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 dcc894e9679d..db74246897a4 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-06 +date: 2024-11-12 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 812ee893cf0e..b7e99dcb1c42 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-06 +date: 2024-11-12 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 9945f6db0c45..7fad45ddc266 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-06 +date: 2024-11-12 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 5489bbd174ac..017149429425 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_screenshotting_server.mdx b/api_docs/kbn_screenshotting_server.mdx index f781445d53c0..61e0f8fbcff1 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-06 +date: 2024-11-12 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.mdx b/api_docs/kbn_search_api_keys_components.mdx index 0cc797de472d..ed9420b3658c 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-06 +date: 2024-11-12 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 5d3034682cbb..79819d9fc6fc 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-06 +date: 2024-11-12 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 3259c4e865d1..c5f4e270e01d 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-06 +date: 2024-11-12 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 de9957ce4b93..a4721ab941fb 100644 --- a/api_docs/kbn_search_connectors.devdocs.json +++ b/api_docs/kbn_search_connectors.devdocs.json @@ -1338,6 +1338,31 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.getConnectorsDict", + "type": "Function", + "tags": [], + "label": "getConnectorsDict", + "description": [], + "signature": [ + "() => Record" + ], + "path": "packages/kbn-search-connectors/constants/connectors.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/search-connectors", "id": "def-common.isCategoryEntry", @@ -3575,6 +3600,73 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorClientSideDefinition", + "type": "Interface", + "tags": [], + "label": "ConnectorClientSideDefinition", + "description": [], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorClientSideDefinition.docsUrl", + "type": "string", + "tags": [], + "label": "docsUrl", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorClientSideDefinition.externalAuthDocsUrl", + "type": "string", + "tags": [], + "label": "externalAuthDocsUrl", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorClientSideDefinition.externalDocsUrl", + "type": "string", + "tags": [], + "label": "externalDocsUrl", + "description": [], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorClientSideDefinition.platinumOnly", + "type": "CompoundType", + "tags": [], + "label": "platinumOnly", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/search-connectors", "id": "def-common.ConnectorConfigCategoryProperties", @@ -4031,6 +4123,131 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorServerSideDefinition", + "type": "Interface", + "tags": [], + "label": "ConnectorServerSideDefinition", + "description": [], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorServerSideDefinition.categories", + "type": "Array", + "tags": [], + "label": "categories", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorServerSideDefinition.description", + "type": "string", + "tags": [], + "label": "description", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorServerSideDefinition.iconPath", + "type": "string", + "tags": [], + "label": "iconPath", + "description": [], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorServerSideDefinition.isBeta", + "type": "boolean", + "tags": [], + "label": "isBeta", + "description": [], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorServerSideDefinition.isNative", + "type": "boolean", + "tags": [], + "label": "isNative", + "description": [], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorServerSideDefinition.isTechPreview", + "type": "CompoundType", + "tags": [], + "label": "isTechPreview", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorServerSideDefinition.keywords", + "type": "Array", + "tags": [], + "label": "keywords", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorServerSideDefinition.name", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorServerSideDefinition.serviceType", + "type": "string", + "tags": [], + "label": "serviceType", + "description": [], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/search-connectors", "id": "def-common.ConnectorStats", @@ -6405,6 +6622,28 @@ } ], "misc": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.CONNECTOR_DEFINITIONS", + "type": "Array", + "tags": [], + "label": "CONNECTOR_DEFINITIONS", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.ConnectorServerSideDefinition", + "text": "ConnectorServerSideDefinition" + }, + "[]" + ], + "path": "packages/kbn-search-connectors/constants/connectors.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/search-connectors", "id": "def-common.ConnectorConfiguration", @@ -6475,6 +6714,35 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.ConnectorDefinition", + "type": "Type", + "tags": [], + "label": "ConnectorDefinition", + "description": [], + "signature": [ + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.ConnectorClientSideDefinition", + "text": "ConnectorClientSideDefinition" + }, + " & ", + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.ConnectorServerSideDefinition", + "text": "ConnectorServerSideDefinition" + } + ], + "path": "packages/kbn-search-connectors/types/connector_definition.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/search-connectors", "id": "def-common.ConnectorDocument", @@ -6896,6 +7164,21 @@ } ], "objects": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.docLinks", + "type": "Object", + "tags": [], + "label": "docLinks", + "description": [], + "signature": [ + "ESDocLinks" + ], + "path": "packages/kbn-search-connectors/constants/doc_links.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/search-connectors", "id": "def-common.LicenseContext", @@ -8364,10 +8647,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -8375,7 +8658,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -8386,7 +8669,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -8402,7 +8685,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -8413,7 +8696,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -8431,10 +8714,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -8442,7 +8725,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.azure_blob_storage.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -13586,10 +13869,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -13597,7 +13880,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -13608,7 +13891,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -13624,7 +13907,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -13635,7 +13918,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -13653,10 +13936,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.FeatureName.DOCUMENT_LEVEL_SECURITY", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.DOCUMENT_LEVEL_SECURITY", "type": "Object", "tags": [], - "label": "[FeatureName.DOCUMENT_LEVEL_SECURITY]", + "label": "[DOCUMENT_LEVEL_SECURITY]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -13664,7 +13947,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.FeatureName.DOCUMENT_LEVEL_SECURITY.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.DOCUMENT_LEVEL_SECURITY.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -13680,10 +13963,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -13691,7 +13974,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.confluence.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -15570,10 +15853,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.FeatureName.DOCUMENT_LEVEL_SECURITY", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.DOCUMENT_LEVEL_SECURITY", "type": "Object", "tags": [], - "label": "[FeatureName.DOCUMENT_LEVEL_SECURITY]", + "label": "[DOCUMENT_LEVEL_SECURITY]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -15581,7 +15864,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.FeatureName.DOCUMENT_LEVEL_SECURITY.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.DOCUMENT_LEVEL_SECURITY.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -15597,10 +15880,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -15608,7 +15891,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -15619,7 +15902,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -15635,7 +15918,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -15646,7 +15929,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -15664,10 +15947,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -15675,7 +15958,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.dropbox.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -18560,10 +18843,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -18571,7 +18854,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -18582,7 +18865,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -18598,7 +18881,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -18609,7 +18892,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -18627,10 +18910,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -18638,7 +18921,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.github.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -19698,10 +19981,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -19709,7 +19992,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -19720,7 +20003,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -19736,7 +20019,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -19747,7 +20030,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -19765,10 +20048,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.FeatureName.DOCUMENT_LEVEL_SECURITY", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.DOCUMENT_LEVEL_SECURITY", "type": "Object", "tags": [], - "label": "[FeatureName.DOCUMENT_LEVEL_SECURITY]", + "label": "[DOCUMENT_LEVEL_SECURITY]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -19776,7 +20059,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.FeatureName.DOCUMENT_LEVEL_SECURITY.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.DOCUMENT_LEVEL_SECURITY.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -19792,10 +20075,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -19803,7 +20086,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.gmail.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -19867,10 +20150,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.google_cloud_storage.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.google_cloud_storage.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -19878,7 +20161,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.google_cloud_storage.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.google_cloud_storage.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -22347,10 +22630,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.google_drive.features.FeatureName.DOCUMENT_LEVEL_SECURITY", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.google_drive.features.DOCUMENT_LEVEL_SECURITY", "type": "Object", "tags": [], - "label": "[FeatureName.DOCUMENT_LEVEL_SECURITY]", + "label": "[DOCUMENT_LEVEL_SECURITY]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -22358,7 +22641,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.google_drive.features.FeatureName.DOCUMENT_LEVEL_SECURITY.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.google_drive.features.DOCUMENT_LEVEL_SECURITY.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -22374,10 +22657,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.google_drive.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.google_drive.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -22385,7 +22668,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.google_drive.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.google_drive.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -25475,10 +25758,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -25486,7 +25769,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -25497,7 +25780,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -25513,7 +25796,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -25524,7 +25807,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -25542,10 +25825,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.FeatureName.DOCUMENT_LEVEL_SECURITY", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.DOCUMENT_LEVEL_SECURITY", "type": "Object", "tags": [], - "label": "[FeatureName.DOCUMENT_LEVEL_SECURITY]", + "label": "[DOCUMENT_LEVEL_SECURITY]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -25553,7 +25836,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.FeatureName.DOCUMENT_LEVEL_SECURITY.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.DOCUMENT_LEVEL_SECURITY.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -25569,10 +25852,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -25580,7 +25863,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.jira.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -28481,10 +28764,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.FeatureName.FILTERING_ADVANCED_CONFIG", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.FILTERING_ADVANCED_CONFIG", "type": "boolean", "tags": [], - "label": "[FeatureName.FILTERING_ADVANCED_CONFIG]", + "label": "[FILTERING_ADVANCED_CONFIG]", "description": [], "signature": [ "true" @@ -28495,10 +28778,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.FeatureName.FILTERING_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.FILTERING_RULES", "type": "boolean", "tags": [], - "label": "[FeatureName.FILTERING_RULES]", + "label": "[FILTERING_RULES]", "description": [], "signature": [ "true" @@ -28509,10 +28792,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -28520,7 +28803,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -28531,7 +28814,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -28547,7 +28830,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -28558,7 +28841,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mongodb.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -30980,10 +31263,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mssql.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mssql.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -30991,7 +31274,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mssql.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mssql.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -31002,7 +31285,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mssql.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mssql.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -31018,7 +31301,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mssql.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mssql.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -31029,7 +31312,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mssql.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mssql.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -33057,10 +33340,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mysql.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mysql.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -33068,7 +33351,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mysql.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mysql.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -33079,7 +33362,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mysql.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mysql.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -33095,7 +33378,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mysql.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mysql.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -33106,7 +33389,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mysql.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.mysql.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -34392,10 +34675,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -34403,7 +34686,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -34414,7 +34697,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -34430,7 +34713,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -34441,7 +34724,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -34459,10 +34742,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -34470,7 +34753,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.network_drive.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -35532,10 +35815,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.notion.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.notion.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -35543,7 +35826,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.notion.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.notion.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -35554,7 +35837,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.notion.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.notion.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -35570,7 +35853,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.notion.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.notion.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -35581,7 +35864,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.notion.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.notion.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -37065,10 +37348,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -37076,7 +37359,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -37087,7 +37370,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -37103,7 +37386,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -37114,7 +37397,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -37132,10 +37415,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.FeatureName.DOCUMENT_LEVEL_SECURITY", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.DOCUMENT_LEVEL_SECURITY", "type": "Object", "tags": [], - "label": "[FeatureName.DOCUMENT_LEVEL_SECURITY]", + "label": "[DOCUMENT_LEVEL_SECURITY]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -37143,7 +37426,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.FeatureName.DOCUMENT_LEVEL_SECURITY.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.DOCUMENT_LEVEL_SECURITY.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -37159,10 +37442,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -37170,7 +37453,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.onedrive.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -39373,10 +39656,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -39384,7 +39667,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -39395,7 +39678,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -39411,7 +39694,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -39422,7 +39705,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.oracle.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -42095,10 +42378,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -42106,7 +42389,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -42117,7 +42400,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -42133,7 +42416,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -42144,7 +42427,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -42162,10 +42445,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.FeatureName.DOCUMENT_LEVEL_SECURITY", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.DOCUMENT_LEVEL_SECURITY", "type": "Object", "tags": [], - "label": "[FeatureName.DOCUMENT_LEVEL_SECURITY]", + "label": "[DOCUMENT_LEVEL_SECURITY]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -42173,7 +42456,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.FeatureName.DOCUMENT_LEVEL_SECURITY.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.DOCUMENT_LEVEL_SECURITY.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -42189,10 +42472,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -42200,7 +42483,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.outlook.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -44420,10 +44703,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.postgresql.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.postgresql.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -44431,7 +44714,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.postgresql.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.postgresql.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -44442,7 +44725,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.postgresql.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.postgresql.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -44458,7 +44741,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.postgresql.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.postgresql.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -44469,7 +44752,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.postgresql.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.postgresql.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -46133,10 +46416,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.s3.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.s3.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -46144,7 +46427,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.s3.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.s3.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -46155,7 +46438,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.s3.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.s3.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -46171,7 +46454,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.s3.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.s3.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -46182,7 +46465,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.s3.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.s3.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -46248,10 +46531,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -46259,7 +46542,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -46270,7 +46553,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -46286,7 +46569,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -46297,7 +46580,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -46315,10 +46598,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -46326,7 +46609,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.salesforce.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -48998,10 +49281,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -49009,7 +49292,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -49020,7 +49303,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -49036,7 +49319,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -49047,7 +49330,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -49065,10 +49348,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -49076,7 +49359,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.servicenow.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -51738,10 +52021,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -51749,7 +52032,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -51760,7 +52043,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -51776,7 +52059,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -51787,7 +52070,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -51805,10 +52088,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.FeatureName.DOCUMENT_LEVEL_SECURITY", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.DOCUMENT_LEVEL_SECURITY", "type": "Object", "tags": [], - "label": "[FeatureName.DOCUMENT_LEVEL_SECURITY]", + "label": "[DOCUMENT_LEVEL_SECURITY]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -51816,7 +52099,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.FeatureName.DOCUMENT_LEVEL_SECURITY.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.DOCUMENT_LEVEL_SECURITY.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -51832,10 +52115,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -51843,7 +52126,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_online.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -54308,10 +54591,10 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.SYNC_RULES", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.SYNC_RULES", "type": "Object", "tags": [], - "label": "[FeatureName.SYNC_RULES]", + "label": "[SYNC_RULES]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -54319,7 +54602,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.SYNC_RULES.advanced", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.SYNC_RULES.advanced", "type": "Object", "tags": [], "label": "advanced", @@ -54330,7 +54613,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.SYNC_RULES.advanced.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.SYNC_RULES.advanced.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -54346,7 +54629,7 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.SYNC_RULES.basic", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.SYNC_RULES.basic", "type": "Object", "tags": [], "label": "basic", @@ -54357,7 +54640,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.SYNC_RULES.basic.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.SYNC_RULES.basic.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -54375,10 +54658,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.DOCUMENT_LEVEL_SECURITY", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.DOCUMENT_LEVEL_SECURITY", "type": "Object", "tags": [], - "label": "[FeatureName.DOCUMENT_LEVEL_SECURITY]", + "label": "[DOCUMENT_LEVEL_SECURITY]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -54386,7 +54669,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.DOCUMENT_LEVEL_SECURITY.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.DOCUMENT_LEVEL_SECURITY.enabled", "type": "boolean", "tags": [], "label": "enabled", @@ -54402,10 +54685,10 @@ }, { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.INCREMENTAL_SYNC", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.INCREMENTAL_SYNC", "type": "Object", "tags": [], - "label": "[FeatureName.INCREMENTAL_SYNC]", + "label": "[INCREMENTAL_SYNC]", "description": [], "path": "packages/kbn-search-connectors/types/native_connectors.ts", "deprecated": false, @@ -54413,7 +54696,7 @@ "children": [ { "parentPluginId": "@kbn/search-connectors", - "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.FeatureName.INCREMENTAL_SYNC.enabled", + "id": "def-common.NATIVE_CONNECTOR_DEFINITIONS.sharepoint_server.features.INCREMENTAL_SYNC.enabled", "type": "boolean", "tags": [], "label": "enabled", diff --git a/api_docs/kbn_search_connectors.mdx b/api_docs/kbn_search_connectors.mdx index c8b6916ebdb6..1acdad333882 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-06 +date: 2024-11-12 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 | |-------------------|-----------|------------------------|-----------------| -| 3929 | 0 | 3929 | 0 | +| 3948 | 0 | 3948 | 0 | ## Common diff --git a/api_docs/kbn_search_errors.mdx b/api_docs/kbn_search_errors.mdx index d369ed514a92..5c32759e084f 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-06 +date: 2024-11-12 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 d530e76851f2..1c2ca8ebe121 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-06 +date: 2024-11-12 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 869368f466da..b783e3a2eaf0 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-06 +date: 2024-11-12 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 dc136dda1746..0b2b651652dc 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-06 +date: 2024-11-12 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.devdocs.json b/api_docs/kbn_search_types.devdocs.json index c36995b3791c..d09d6a63dd0b 100644 --- a/api_docs/kbn_search_types.devdocs.json +++ b/api_docs/kbn_search_types.devdocs.json @@ -825,6 +825,22 @@ "path": "packages/kbn-search-types/src/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/search-types", + "id": "def-common.ISearchOptions.stream", + "type": "CompoundType", + "tags": [], + "label": "stream", + "description": [ + "\nWhen set es results are streamed back to the caller without any parsing of the content." + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-search-types/src/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -979,7 +995,7 @@ "section": "def-common.KibanaExecutionContext", "text": "KibanaExecutionContext" }, - " | undefined; isStored?: boolean | undefined; isRestore?: boolean | undefined; sessionId?: string | undefined; strategy?: string | undefined; legacyHitsTotal?: boolean | undefined; isSearchStored?: boolean | undefined; retrieveResults?: boolean | undefined; }" + " | undefined; isStored?: boolean | undefined; isRestore?: boolean | undefined; sessionId?: string | undefined; stream?: boolean | undefined; strategy?: string | undefined; legacyHitsTotal?: boolean | undefined; isSearchStored?: boolean | undefined; retrieveResults?: boolean | undefined; }" ], "path": "packages/kbn-search-types/src/types.ts", "deprecated": false, diff --git a/api_docs/kbn_search_types.mdx b/api_docs/kbn_search_types.mdx index 481fbfd5375c..248eb3a1df12 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-types'] --- import kbnSearchTypesObj from './kbn_search_types.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 | |-------------------|-----------|------------------------|-----------------| -| 50 | 0 | 25 | 0 | +| 51 | 0 | 25 | 0 | ## Common diff --git a/api_docs/kbn_security_api_key_management.mdx b/api_docs/kbn_security_api_key_management.mdx index 96931f0fea70..dbb86b136acb 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-06 +date: 2024-11-12 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 c6b3bd4d3926..20e1cbf0e18a 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-06 +date: 2024-11-12 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 f44a8d3599bb..fe630c194a15 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-06 +date: 2024-11-12 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.mdx b/api_docs/kbn_security_form_components.mdx index 3c4c44c30733..0ed1baaaded6 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-06 +date: 2024-11-12 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 6a154e01e6bb..84392a192248 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-06 +date: 2024-11-12 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 5be1f300704a..fd13c63ea575 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-06 +date: 2024-11-12 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 6e425733fa92..e7fdb4d05fd5 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-06 +date: 2024-11-12 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.devdocs.json b/api_docs/kbn_security_plugin_types_server.devdocs.json index 4f11b25ee54f..3594642ab41a 100644 --- a/api_docs/kbn_security_plugin_types_server.devdocs.json +++ b/api_docs/kbn_security_plugin_types_server.devdocs.json @@ -4893,6 +4893,18 @@ "plugin": "entityManager", "path": "x-pack/plugins/entity_manager/server/routes/enablement/disable.ts" }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/server/lib/helpers/get_random_sampler/index.ts" + }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/server/routes/agent_keys/get_agent_keys_privileges.ts" + }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/server/routes/fleet/is_superuser.ts" + }, { "plugin": "serverlessSearch", "path": "x-pack/plugins/serverless_search/server/routes/api_key_routes.ts" @@ -4913,18 +4925,6 @@ "plugin": "upgradeAssistant", "path": "x-pack/plugins/upgrade_assistant/server/lib/reindexing/credential_store.ts" }, - { - "plugin": "apm", - "path": "x-pack/plugins/observability_solution/apm/server/lib/helpers/get_random_sampler/index.ts" - }, - { - "plugin": "apm", - "path": "x-pack/plugins/observability_solution/apm/server/routes/agent_keys/get_agent_keys_privileges.ts" - }, - { - "plugin": "apm", - "path": "x-pack/plugins/observability_solution/apm/server/routes/fleet/is_superuser.ts" - }, { "plugin": "synthetics", "path": "x-pack/plugins/observability_solution/synthetics/server/synthetics_service/get_api_key.ts" diff --git a/api_docs/kbn_security_plugin_types_server.mdx b/api_docs/kbn_security_plugin_types_server.mdx index 400dd93aa8bc..206a5972bd9d 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-06 +date: 2024-11-12 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 40a1a6802963..0a310c07fb5d 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-06 +date: 2024-11-12 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.mdx b/api_docs/kbn_security_solution_distribution_bar.mdx index 6adbc3609f42..ed1ff48e2f75 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-06 +date: 2024-11-12 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 9d72a9eb57ff..0b1037a37945 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-06 +date: 2024-11-12 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 6eafdf73a63c..56252d485c86 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-06 +date: 2024-11-12 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 377d20c278ea..be7ebd0a51be 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-06 +date: 2024-11-12 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 35d22a6270ee..ab1043d3a23e 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-06 +date: 2024-11-12 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 75135bcfbdd1..7fa49d6c162b 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-06 +date: 2024-11-12 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 dbfc948ee909..3f42189484f9 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-06 +date: 2024-11-12 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 c0c8cdbfc660..e53c5eed42c8 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-06 +date: 2024-11-12 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 83fc583bce93..cf035893cf01 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-06 +date: 2024-11-12 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 3f0fd5c701c9..aad0fae8d8e1 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-06 +date: 2024-11-12 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 1028bb381817..5633cc6d7e02 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-06 +date: 2024-11-12 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 4bcfb6c90f2a..8f657380a69a 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-06 +date: 2024-11-12 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 0ae565cddeb4..ec3f360c09e2 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-06 +date: 2024-11-12 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 61d41965abe6..2b217fc98c40 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-06 +date: 2024-11-12 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 4cc35362ecf0..878a65839bfe 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-06 +date: 2024-11-12 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 976f83ddc0c3..ea0ff8468331 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-06 +date: 2024-11-12 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 855c71e98b92..0488ac71876c 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-06 +date: 2024-11-12 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 759611721e01..f7ad8bea1f46 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-06 +date: 2024-11-12 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 6241e6c6fb2e..0367555d973d 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-06 +date: 2024-11-12 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 ca7aecda1a62..9d0cc192b609 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-06 +date: 2024-11-12 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 3ddce4284085..b240f2c990ec 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-06 +date: 2024-11-12 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 035ab489bd77..9be0aebca5bb 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index c46d0c4b1589..d5283e51a4cc 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-06 +date: 2024-11-12 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 3a0a2fa8f40b..b8ee88710751 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-06 +date: 2024-11-12 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 41b597ed16dd..8ceead4e3a7f 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-06 +date: 2024-11-12 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 7f951a2310f4..6dba800e4fdb 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-06 +date: 2024-11-12 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 19e80a910578..2196a4bc7b4c 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-06 +date: 2024-11-12 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 69a691e2cd73..0c5fe48102b3 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-06 +date: 2024-11-12 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 84e00c6b9ab6..c53bdd719a67 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-06 +date: 2024-11-12 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 15bfaeba3fd1..cb345cadee06 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-06 +date: 2024-11-12 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 afdb4a89c318..a98951ad472d 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-06 +date: 2024-11-12 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 5123a940060e..6277489025c9 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-06 +date: 2024-11-12 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 7c9645ac3490..d401be14dd28 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-06 +date: 2024-11-12 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 4b94e7103984..bc6f940e801e 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-06 +date: 2024-11-12 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 db6c2f408a58..4df27618fc84 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-06 +date: 2024-11-12 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 94bc572325e5..52ac2d321f70 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-06 +date: 2024-11-12 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 88b20f452e3b..bcd7c251dc32 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-06 +date: 2024-11-12 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 344476d7df5a..2d1a9fba09bc 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-06 +date: 2024-11-12 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 e519675c4567..2e1eebaeeb40 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-06 +date: 2024-11-12 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 a52d43012c3d..49efcf650726 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-06 +date: 2024-11-12 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 4fa9c5672463..4005ee46a345 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-06 +date: 2024-11-12 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 ae27ff8ac008..2eb3dd62aaab 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-06 +date: 2024-11-12 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 bd5812d9dfce..7bc7d631581f 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-06 +date: 2024-11-12 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 937eddd87590..12ae3a987c04 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-06 +date: 2024-11-12 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 29b25087063d..58741471353f 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-06 +date: 2024-11-12 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 70f7bec5e123..e12e520c65aa 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-06 +date: 2024-11-12 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 8636050cd948..f594b69d93e5 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-06 +date: 2024-11-12 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 a8e80dbe66ea..69c62f3469c2 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-06 +date: 2024-11-12 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 c569f3cf369e..fe4e8b450057 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-06 +date: 2024-11-12 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 2ddd4eb7103e..5b9d0f3e9707 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-06 +date: 2024-11-12 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 1e6d2f7b466c..366b13fad700 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-06 +date: 2024-11-12 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 53afc6aaf71f..90438320f47b 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-06 +date: 2024-11-12 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 6a6e4d64a47e..123431a8be24 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-06 +date: 2024-11-12 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 8e79713a94a1..d601c44e161c 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-06 +date: 2024-11-12 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 b15884536e73..ce5b632cc677 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-06 +date: 2024-11-12 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 e69890fa9cd5..868bc47939dd 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-06 +date: 2024-11-12 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 792613dfd5f2..6a30f35b896a 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-06 +date: 2024-11-12 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 f24be08232ca..ae3ebda7ccc3 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-06 +date: 2024-11-12 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 63acf1a59daa..b08c2aeeb6b4 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-06 +date: 2024-11-12 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 d53e2ac45347..e7ad6701c0ec 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-06 +date: 2024-11-12 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 e1e84bd59d25..3b530e1d3504 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-06 +date: 2024-11-12 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 79d1118a07eb..9bde826c3086 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-06 +date: 2024-11-12 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 c9c1cfc96348..6dae878b9b36 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-06 +date: 2024-11-12 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 275385b07984..e7e40f494699 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-06 +date: 2024-11-12 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 35d1edf7e71c..7e8fb4207f48 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-06 +date: 2024-11-12 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 d45d34513665..3c65e02bc8af 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-06 +date: 2024-11-12 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 4b344e472c7d..3da736728a33 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-06 +date: 2024-11-12 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 3c49b24d9151..13337242d1f9 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-06 +date: 2024-11-12 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 d9976ed9238c..12fd4e5b08cf 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-06 +date: 2024-11-12 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 3eb303b58dea..2154e28257be 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-06 +date: 2024-11-12 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 703da897352a..0213b6758069 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-06 +date: 2024-11-12 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 73cb85009153..c62fa01ec55f 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-06 +date: 2024-11-12 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 ff955a49e0ff..e7f71b4202e1 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-06 +date: 2024-11-12 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 cf61470901ca..a1dd4752be3c 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index 014c96554d12..65288d331330 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-06 +date: 2024-11-12 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 84501ccbf4bb..4ce54ed82db6 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-06 +date: 2024-11-12 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 15bdf6168585..bb4311fbbe76 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-06 +date: 2024-11-12 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 787bd7e7a724..5f1f5f18cde6 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-06 +date: 2024-11-12 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 f02ccb725fc4..3d544b8d6aec 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-06 +date: 2024-11-12 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 7d38924787b7..fba0e8dac86a 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-06 +date: 2024-11-12 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 bff6fb3c0337..91f1966b7116 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-06 +date: 2024-11-12 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 6c10290d71ab..2acd7cb283d4 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-06 +date: 2024-11-12 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 c0db1b750245..1ccfe00076c4 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-06 +date: 2024-11-12 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 113e214660f6..bbe9eaf09a28 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-06 +date: 2024-11-12 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 d2da29691f71..bdfd0bec4dcc 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-06 +date: 2024-11-12 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 98bb7de4622d..55dce0b7c0d9 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.devdocs.json b/api_docs/kbn_test.devdocs.json index 3407196ddb81..f00d113bde3f 100644 --- a/api_docs/kbn_test.devdocs.json +++ b/api_docs/kbn_test.devdocs.json @@ -1711,7 +1711,15 @@ "label": "getApiCredentialsForRole", "description": [], "signature": [ - "(role: string) => Promise<{ Cookie: string; }>" + "(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, @@ -1731,6 +1739,28 @@ "deprecated": false, "trackAdoption": false, "isRequired": true + }, + { + "parentPluginId": "@kbn/test", + "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": [] @@ -1743,7 +1773,15 @@ "label": "getInteractiveUserSessionCookieWithRoleScope", "description": [], "signature": [ - "(role: string) => Promise" + "(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, @@ -1763,6 +1801,28 @@ "deprecated": false, "trackAdoption": false, "isRequired": true + }, + { + "parentPluginId": "@kbn/test", + "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": [] @@ -4722,6 +4782,31 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.GetCookieOptions", + "type": "Interface", + "tags": [], + "label": "GetCookieOptions", + "description": [], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/test", + "id": "def-common.GetCookieOptions.forceNewSession", + "type": "boolean", + "tags": [], + "label": "forceNewSession", + "description": [], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/test", "id": "def-common.HostOptions", diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index b2bf2f84ea7a..832fc1690f20 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 316 | 4 | 268 | 14 | +| 320 | 4 | 272 | 14 | ## Common diff --git a/api_docs/kbn_test_eui_helpers.mdx b/api_docs/kbn_test_eui_helpers.mdx index be6eab235f93..7fafe9cc32bc 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-06 +date: 2024-11-12 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.devdocs.json b/api_docs/kbn_test_jest_helpers.devdocs.json index a38564069270..805e169ca39b 100644 --- a/api_docs/kbn_test_jest_helpers.devdocs.json +++ b/api_docs/kbn_test_jest_helpers.devdocs.json @@ -1006,7 +1006,7 @@ "label": "renderReactTestingLibraryWithI18n", "description": [], "signature": [ - "(ui: React.ReactElement>, options?: Omit<", + "(ui: React.ReactNode, options?: Omit<", "RenderOptions", ">, options?: Omit<", + "[ui: React.ReactNode, options?: Omit<", "RenderOptions", " | undefined; highlight?: Record | undefined; inner_hits?: Record | undefined; matched_queries?: string[] | undefined; _nested?: ", + "> | undefined; matched_queries?: string[] | Record | undefined; _nested?: ", "SearchNestedIdentity", - " | undefined; _ignored?: string[] | undefined; ignored_field_values?: Record | undefined; _shard?: string | undefined; _node?: string | undefined; _routing?: string | undefined; _rank?: number | undefined; _seq_no?: number | undefined; _primary_term?: number | undefined; _version?: number | undefined; sort?: ", + " | undefined; _ignored?: string[] | undefined; ignored_field_values?: Record | undefined; _shard?: string | undefined; _node?: string | undefined; _routing?: string | undefined; _rank?: number | undefined; _seq_no?: number | undefined; _primary_term?: number | undefined; _version?: number | undefined; sort?: ", "SortResults", " | undefined; }>; find: (findParams: { query?: string | undefined; start?: string | undefined; end?: string | undefined; sloId?: string | undefined; sloInstanceId?: string | undefined; serviceName?: string | undefined; filter?: string | undefined; size?: number | undefined; }) => Promise<{ items: { id: string | undefined; annotation: { title: string; 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; }[]; total: number; }>; delete: (deleteParams: { id: string; }) => Promise<", "DeleteByQueryResponse", @@ -12817,9 +12817,9 @@ "ExplainExplanation", " | undefined; fields?: Record | undefined; highlight?: Record | undefined; inner_hits?: Record | undefined; matched_queries?: string[] | undefined; _nested?: ", + "> | undefined; matched_queries?: string[] | Record | undefined; _nested?: ", "SearchNestedIdentity", - " | undefined; _ignored?: string[] | undefined; ignored_field_values?: Record | undefined; _shard?: string | undefined; _node?: string | undefined; _routing?: string | undefined; _rank?: number | undefined; _seq_no?: number | undefined; _primary_term?: number | undefined; _version?: number | undefined; sort?: ", + " | undefined; _ignored?: string[] | undefined; ignored_field_values?: Record | undefined; _shard?: string | undefined; _node?: string | undefined; _routing?: string | undefined; _rank?: number | undefined; _seq_no?: number | undefined; _primary_term?: number | undefined; _version?: number | undefined; sort?: ", "SortResults", " | undefined; }>; find: (findParams: { query?: string | undefined; start?: string | undefined; end?: string | undefined; sloId?: string | undefined; sloInstanceId?: string | undefined; serviceName?: string | undefined; filter?: string | undefined; size?: number | undefined; }) => Promise<{ items: { id: string | undefined; annotation: { title: string; 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; }[]; total: number; }>; delete: (deleteParams: { id: string; }) => Promise<", "DeleteByQueryResponse", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 3814295b9108..9f014ee4f504 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-06 +date: 2024-11-12 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 fb3350bd038f..938513b0d6f5 100644 --- a/api_docs/observability_a_i_assistant.devdocs.json +++ b/api_docs/observability_a_i_assistant.devdocs.json @@ -1186,21 +1186,24 @@ }, { "parentPluginId": "observabilityAIAssistant", - "id": "def-public.KnowledgeBaseEntry.text", + "id": "def-public.KnowledgeBaseEntry.title", "type": "string", "tags": [], - "label": "text", + "label": "title", "description": [], + "signature": [ + "string | undefined" + ], "path": "x-pack/plugins/observability_solution/observability_ai_assistant/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "observabilityAIAssistant", - "id": "def-public.KnowledgeBaseEntry.doc_id", + "id": "def-public.KnowledgeBaseEntry.text", "type": "string", "tags": [], - "label": "doc_id", + "label": "text", "description": [], "path": "x-pack/plugins/observability_solution/observability_ai_assistant/common/types.ts", "deprecated": false, @@ -2184,7 +2187,7 @@ "label": "callApi", "description": [], "signature": [ - "(endpoint: TEndpoint, ...args: MaybeOptionalArgs<", + "(endpoint: TEndpoint, ...args: MaybeOptionalArgs<", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -2226,6 +2229,8 @@ "TypeC", "<{ id: ", "StringC", + "; title: ", + "StringC", "; text: ", "BrandC", "<", @@ -2262,14 +2267,52 @@ "UnionC", "<[", "LiteralC", - "<\"assistant_summarization\">, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".AssistantSummarization>, ", "LiteralC", - "<\"user_entry\">, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".UserEntry>, ", "LiteralC", - "<\"elastic\">]>; }>]>; }>, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".Elastic>]>; }>]>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", ", void, ", "ObservabilityAIAssistantRouteCreateOptions", + ">; \"GET /internal/observability_ai_assistant/kb/user_instructions\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/observability_ai_assistant/kb/user_instructions\", undefined, ", + "ObservabilityAIAssistantRouteHandlerResources", + ", { userInstructions: (", + "Instruction", + " & { public?: boolean | undefined; })[]; }, ", + "ObservabilityAIAssistantRouteCreateOptions", ">; \"POST /internal/observability_ai_assistant/kb/entries/import\": ", { "pluginId": "@kbn/server-route-repository-utils", @@ -2285,9 +2328,13 @@ "<{ entries: ", "ArrayC", "<", + "IntersectionC", + "<[", "TypeC", "<{ id: ", "StringC", + "; title: ", + "StringC", "; text: ", "BrandC", "<", @@ -2300,23 +2347,61 @@ "section": "def-common.NonEmptyStringBrand", "text": "NonEmptyStringBrand" }, - ">; }>>; }>; }>, ", - "ObservabilityAIAssistantRouteHandlerResources", - ", void, ", - "ObservabilityAIAssistantRouteCreateOptions", - ">; \"GET /internal/observability_ai_assistant/kb/user_instructions\": ", + ">; }>, ", + "PartialC", + "<{ confidence: ", + "UnionC", + "<[", + "LiteralC", + "<\"low\">, ", + "LiteralC", + "<\"medium\">, ", + "LiteralC", + "<\"high\">]>; is_correction: ", + "Type", + "; public: ", + "Type", + "; labels: ", + "RecordC", + "<", + "StringC", + ", ", + "StringC", + ">; role: ", + "UnionC", + "<[", + "LiteralC", + "<", { - "pluginId": "@kbn/server-route-repository-utils", + "pluginId": "observabilityAIAssistant", "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.ServerRoute", - "text": "ServerRoute" + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" }, - "<\"GET /internal/observability_ai_assistant/kb/user_instructions\", undefined, ", + ".AssistantSummarization>, ", + "LiteralC", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".UserEntry>, ", + "LiteralC", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".Elastic>]>; }>]>>; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", - ", { userInstructions: (", - "Instruction", - " & { public?: boolean | undefined; })[]; }, ", + ", void, ", "ObservabilityAIAssistantRouteCreateOptions", ">; \"PUT /internal/observability_ai_assistant/kb/user_instructions\": ", { @@ -2424,7 +2509,7 @@ "TypeC", "<{ body: ", "TypeC", - "<{ id: ", + "<{ title: ", "StringC", "; text: ", "BrandC", @@ -2448,13 +2533,7 @@ "LiteralC", "<\"high\">]>; is_correction: ", "Type", - "; type: ", - "UnionC", - "<[", - "LiteralC", - "<\"user_instruction\">, ", - "LiteralC", - "<\"contextual\">]>; public: ", + "; public: ", "Type", "; labels: ", "RecordC", @@ -2794,7 +2873,7 @@ "IntersectionC", "<[", "PartialC", - "<{ doc_id: ", + "<{ id: ", "StringC", "; }>, ", "TypeC", @@ -2900,7 +2979,7 @@ "IntersectionC", "<[", "PartialC", - "<{ doc_id: ", + "<{ id: ", "StringC", "; }>, ", "TypeC", @@ -3088,6 +3167,8 @@ "TypeC", "<{ id: ", "StringC", + "; title: ", + "StringC", "; text: ", "BrandC", "<", @@ -3124,14 +3205,52 @@ "UnionC", "<[", "LiteralC", - "<\"assistant_summarization\">, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".AssistantSummarization>, ", "LiteralC", - "<\"user_entry\">, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".UserEntry>, ", "LiteralC", - "<\"elastic\">]>; }>]>; }>, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".Elastic>]>; }>]>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", ", void, ", "ObservabilityAIAssistantRouteCreateOptions", + ">; \"GET /internal/observability_ai_assistant/kb/user_instructions\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/observability_ai_assistant/kb/user_instructions\", undefined, ", + "ObservabilityAIAssistantRouteHandlerResources", + ", { userInstructions: (", + "Instruction", + " & { public?: boolean | undefined; })[]; }, ", + "ObservabilityAIAssistantRouteCreateOptions", ">; \"POST /internal/observability_ai_assistant/kb/entries/import\": ", { "pluginId": "@kbn/server-route-repository-utils", @@ -3147,9 +3266,13 @@ "<{ entries: ", "ArrayC", "<", + "IntersectionC", + "<[", "TypeC", "<{ id: ", "StringC", + "; title: ", + "StringC", "; text: ", "BrandC", "<", @@ -3162,23 +3285,61 @@ "section": "def-common.NonEmptyStringBrand", "text": "NonEmptyStringBrand" }, - ">; }>>; }>; }>, ", - "ObservabilityAIAssistantRouteHandlerResources", - ", void, ", - "ObservabilityAIAssistantRouteCreateOptions", - ">; \"GET /internal/observability_ai_assistant/kb/user_instructions\": ", + ">; }>, ", + "PartialC", + "<{ confidence: ", + "UnionC", + "<[", + "LiteralC", + "<\"low\">, ", + "LiteralC", + "<\"medium\">, ", + "LiteralC", + "<\"high\">]>; is_correction: ", + "Type", + "; public: ", + "Type", + "; labels: ", + "RecordC", + "<", + "StringC", + ", ", + "StringC", + ">; role: ", + "UnionC", + "<[", + "LiteralC", + "<", { - "pluginId": "@kbn/server-route-repository-utils", + "pluginId": "observabilityAIAssistant", "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.ServerRoute", - "text": "ServerRoute" + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" }, - "<\"GET /internal/observability_ai_assistant/kb/user_instructions\", undefined, ", + ".AssistantSummarization>, ", + "LiteralC", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".UserEntry>, ", + "LiteralC", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".Elastic>]>; }>]>>; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", - ", { userInstructions: (", - "Instruction", - " & { public?: boolean | undefined; })[]; }, ", + ", void, ", "ObservabilityAIAssistantRouteCreateOptions", ">; \"PUT /internal/observability_ai_assistant/kb/user_instructions\": ", { @@ -3286,7 +3447,7 @@ "TypeC", "<{ body: ", "TypeC", - "<{ id: ", + "<{ title: ", "StringC", "; text: ", "BrandC", @@ -3310,13 +3471,7 @@ "LiteralC", "<\"high\">]>; is_correction: ", "Type", - "; type: ", - "UnionC", - "<[", - "LiteralC", - "<\"user_instruction\">, ", - "LiteralC", - "<\"contextual\">]>; public: ", + "; public: ", "Type", "; labels: ", "RecordC", @@ -3656,7 +3811,7 @@ "IntersectionC", "<[", "PartialC", - "<{ doc_id: ", + "<{ id: ", "StringC", "; }>, ", "TypeC", @@ -3762,7 +3917,7 @@ "IntersectionC", "<[", "PartialC", - "<{ doc_id: ", + "<{ id: ", "StringC", "; }>, ", "TypeC", @@ -4671,6 +4826,8 @@ "TypeC", "<{ id: ", "StringC", + "; title: ", + "StringC", "; text: ", "BrandC", "<", @@ -4707,14 +4864,52 @@ "UnionC", "<[", "LiteralC", - "<\"assistant_summarization\">, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".AssistantSummarization>, ", "LiteralC", - "<\"user_entry\">, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".UserEntry>, ", "LiteralC", - "<\"elastic\">]>; }>]>; }>, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".Elastic>]>; }>]>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", ", void, ", "ObservabilityAIAssistantRouteCreateOptions", + ">; \"GET /internal/observability_ai_assistant/kb/user_instructions\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/observability_ai_assistant/kb/user_instructions\", undefined, ", + "ObservabilityAIAssistantRouteHandlerResources", + ", { userInstructions: (", + "Instruction", + " & { public?: boolean | undefined; })[]; }, ", + "ObservabilityAIAssistantRouteCreateOptions", ">; \"POST /internal/observability_ai_assistant/kb/entries/import\": ", { "pluginId": "@kbn/server-route-repository-utils", @@ -4730,38 +4925,80 @@ "<{ entries: ", "ArrayC", "<", + "IntersectionC", + "<[", "TypeC", "<{ id: ", "StringC", + "; title: ", + "StringC", "; text: ", "BrandC", "<", - "StringC", - ", ", + "StringC", + ", ", + { + "pluginId": "@kbn/io-ts-utils", + "scope": "common", + "docId": "kibKbnIoTsUtilsPluginApi", + "section": "def-common.NonEmptyStringBrand", + "text": "NonEmptyStringBrand" + }, + ">; }>, ", + "PartialC", + "<{ confidence: ", + "UnionC", + "<[", + "LiteralC", + "<\"low\">, ", + "LiteralC", + "<\"medium\">, ", + "LiteralC", + "<\"high\">]>; is_correction: ", + "Type", + "; public: ", + "Type", + "; labels: ", + "RecordC", + "<", + "StringC", + ", ", + "StringC", + ">; role: ", + "UnionC", + "<[", + "LiteralC", + "<", { - "pluginId": "@kbn/io-ts-utils", + "pluginId": "observabilityAIAssistant", "scope": "common", - "docId": "kibKbnIoTsUtilsPluginApi", - "section": "def-common.NonEmptyStringBrand", - "text": "NonEmptyStringBrand" + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" }, - ">; }>>; }>; }>, ", - "ObservabilityAIAssistantRouteHandlerResources", - ", void, ", - "ObservabilityAIAssistantRouteCreateOptions", - ">; \"GET /internal/observability_ai_assistant/kb/user_instructions\": ", + ".AssistantSummarization>, ", + "LiteralC", + "<", { - "pluginId": "@kbn/server-route-repository-utils", + "pluginId": "observabilityAIAssistant", "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.ServerRoute", - "text": "ServerRoute" + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" }, - "<\"GET /internal/observability_ai_assistant/kb/user_instructions\", undefined, ", + ".UserEntry>, ", + "LiteralC", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".Elastic>]>; }>]>>; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", - ", { userInstructions: (", - "Instruction", - " & { public?: boolean | undefined; })[]; }, ", + ", void, ", "ObservabilityAIAssistantRouteCreateOptions", ">; \"PUT /internal/observability_ai_assistant/kb/user_instructions\": ", { @@ -4869,7 +5106,7 @@ "TypeC", "<{ body: ", "TypeC", - "<{ id: ", + "<{ title: ", "StringC", "; text: ", "BrandC", @@ -4893,13 +5130,7 @@ "LiteralC", "<\"high\">]>; is_correction: ", "Type", - "; type: ", - "UnionC", - "<[", - "LiteralC", - "<\"user_instruction\">, ", - "LiteralC", - "<\"contextual\">]>; public: ", + "; public: ", "Type", "; labels: ", "RecordC", @@ -5239,7 +5470,7 @@ "IntersectionC", "<[", "PartialC", - "<{ doc_id: ", + "<{ id: ", "StringC", "; }>, ", "TypeC", @@ -5345,7 +5576,7 @@ "IntersectionC", "<[", "PartialC", - "<{ doc_id: ", + "<{ id: ", "StringC", "; }>, ", "TypeC", @@ -5776,6 +6007,8 @@ "TypeC", "<{ id: ", "StringC", + "; title: ", + "StringC", "; text: ", "BrandC", "<", @@ -5812,14 +6045,52 @@ "UnionC", "<[", "LiteralC", - "<\"assistant_summarization\">, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".AssistantSummarization>, ", "LiteralC", - "<\"user_entry\">, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".UserEntry>, ", "LiteralC", - "<\"elastic\">]>; }>]>; }>, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".Elastic>]>; }>]>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", ", void, ", "ObservabilityAIAssistantRouteCreateOptions", + ">; \"GET /internal/observability_ai_assistant/kb/user_instructions\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/observability_ai_assistant/kb/user_instructions\", undefined, ", + "ObservabilityAIAssistantRouteHandlerResources", + ", { userInstructions: (", + "Instruction", + " & { public?: boolean | undefined; })[]; }, ", + "ObservabilityAIAssistantRouteCreateOptions", ">; \"POST /internal/observability_ai_assistant/kb/entries/import\": ", { "pluginId": "@kbn/server-route-repository-utils", @@ -5835,9 +6106,13 @@ "<{ entries: ", "ArrayC", "<", + "IntersectionC", + "<[", "TypeC", "<{ id: ", "StringC", + "; title: ", + "StringC", "; text: ", "BrandC", "<", @@ -5850,23 +6125,61 @@ "section": "def-common.NonEmptyStringBrand", "text": "NonEmptyStringBrand" }, - ">; }>>; }>; }>, ", - "ObservabilityAIAssistantRouteHandlerResources", - ", void, ", - "ObservabilityAIAssistantRouteCreateOptions", - ">; \"GET /internal/observability_ai_assistant/kb/user_instructions\": ", + ">; }>, ", + "PartialC", + "<{ confidence: ", + "UnionC", + "<[", + "LiteralC", + "<\"low\">, ", + "LiteralC", + "<\"medium\">, ", + "LiteralC", + "<\"high\">]>; is_correction: ", + "Type", + "; public: ", + "Type", + "; labels: ", + "RecordC", + "<", + "StringC", + ", ", + "StringC", + ">; role: ", + "UnionC", + "<[", + "LiteralC", + "<", { - "pluginId": "@kbn/server-route-repository-utils", + "pluginId": "observabilityAIAssistant", "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.ServerRoute", - "text": "ServerRoute" + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" }, - "<\"GET /internal/observability_ai_assistant/kb/user_instructions\", undefined, ", + ".AssistantSummarization>, ", + "LiteralC", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".UserEntry>, ", + "LiteralC", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".Elastic>]>; }>]>>; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", - ", { userInstructions: (", - "Instruction", - " & { public?: boolean | undefined; })[]; }, ", + ", void, ", "ObservabilityAIAssistantRouteCreateOptions", ">; \"PUT /internal/observability_ai_assistant/kb/user_instructions\": ", { @@ -5974,7 +6287,7 @@ "TypeC", "<{ body: ", "TypeC", - "<{ id: ", + "<{ title: ", "StringC", "; text: ", "BrandC", @@ -5998,13 +6311,7 @@ "LiteralC", "<\"high\">]>; is_correction: ", "Type", - "; type: ", - "UnionC", - "<[", - "LiteralC", - "<\"user_instruction\">, ", - "LiteralC", - "<\"contextual\">]>; public: ", + "; public: ", "Type", "; labels: ", "RecordC", @@ -6344,7 +6651,7 @@ "IntersectionC", "<[", "PartialC", - "<{ doc_id: ", + "<{ id: ", "StringC", "; }>, ", "TypeC", @@ -6450,7 +6757,7 @@ "IntersectionC", "<[", "PartialC", - "<{ doc_id: ", + "<{ id: ", "StringC", "; }>, ", "TypeC", @@ -6643,7 +6950,7 @@ "label": "ObservabilityAIAssistantAPIEndpoint", "description": [], "signature": [ - "\"POST /internal/observability_ai_assistant/chat\" | \"POST /internal/observability_ai_assistant/chat/recall\" | \"POST /internal/observability_ai_assistant/chat/complete\" | \"POST /api/observability_ai_assistant/chat/complete 2023-10-31\" | \"GET /internal/observability_ai_assistant/conversation/{conversationId}\" | \"POST /internal/observability_ai_assistant/conversations\" | \"POST /internal/observability_ai_assistant/conversation\" | \"PUT /internal/observability_ai_assistant/conversation/{conversationId}\" | \"PUT /internal/observability_ai_assistant/conversation/{conversationId}/title\" | \"DELETE /internal/observability_ai_assistant/conversation/{conversationId}\" | \"GET /internal/observability_ai_assistant/connectors\" | \"GET /internal/observability_ai_assistant/functions\" | \"POST /internal/observability_ai_assistant/functions/recall\" | \"POST /internal/observability_ai_assistant/functions/summarize\" | \"POST /internal/observability_ai_assistant/kb/setup\" | \"GET /internal/observability_ai_assistant/kb/status\" | \"GET /internal/observability_ai_assistant/kb/entries\" | \"PUT /internal/observability_ai_assistant/kb/user_instructions\" | \"GET /internal/observability_ai_assistant/kb/user_instructions\" | \"POST /internal/observability_ai_assistant/kb/entries/import\" | \"POST /internal/observability_ai_assistant/kb/entries/save\" | \"DELETE /internal/observability_ai_assistant/kb/entries/{entryId}\"" + "\"POST /internal/observability_ai_assistant/chat\" | \"POST /internal/observability_ai_assistant/chat/recall\" | \"POST /internal/observability_ai_assistant/chat/complete\" | \"POST /api/observability_ai_assistant/chat/complete 2023-10-31\" | \"GET /internal/observability_ai_assistant/conversation/{conversationId}\" | \"POST /internal/observability_ai_assistant/conversations\" | \"POST /internal/observability_ai_assistant/conversation\" | \"PUT /internal/observability_ai_assistant/conversation/{conversationId}\" | \"PUT /internal/observability_ai_assistant/conversation/{conversationId}/title\" | \"DELETE /internal/observability_ai_assistant/conversation/{conversationId}\" | \"GET /internal/observability_ai_assistant/connectors\" | \"GET /internal/observability_ai_assistant/functions\" | \"POST /internal/observability_ai_assistant/functions/recall\" | \"POST /internal/observability_ai_assistant/functions/summarize\" | \"POST /internal/observability_ai_assistant/kb/setup\" | \"GET /internal/observability_ai_assistant/kb/status\" | \"GET /internal/observability_ai_assistant/kb/entries\" | \"PUT /internal/observability_ai_assistant/kb/user_instructions\" | \"POST /internal/observability_ai_assistant/kb/entries/import\" | \"GET /internal/observability_ai_assistant/kb/user_instructions\" | \"POST /internal/observability_ai_assistant/kb/entries/save\" | \"DELETE /internal/observability_ai_assistant/kb/entries/{entryId}\"" ], "path": "x-pack/plugins/observability_solution/observability_ai_assistant/public/api/index.ts", "deprecated": false, @@ -7406,6 +7713,8 @@ "TypeC", "<{ id: ", "StringC", + "; title: ", + "StringC", "; text: ", "BrandC", "<", @@ -7442,14 +7751,52 @@ "UnionC", "<[", "LiteralC", - "<\"assistant_summarization\">, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".AssistantSummarization>, ", "LiteralC", - "<\"user_entry\">, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".UserEntry>, ", "LiteralC", - "<\"elastic\">]>; }>]>; }>, ", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".Elastic>]>; }>]>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", ", void, ", "ObservabilityAIAssistantRouteCreateOptions", + ">; \"GET /internal/observability_ai_assistant/kb/user_instructions\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/observability_ai_assistant/kb/user_instructions\", undefined, ", + "ObservabilityAIAssistantRouteHandlerResources", + ", { userInstructions: (", + "Instruction", + " & { public?: boolean | undefined; })[]; }, ", + "ObservabilityAIAssistantRouteCreateOptions", ">; \"POST /internal/observability_ai_assistant/kb/entries/import\": ", { "pluginId": "@kbn/server-route-repository-utils", @@ -7465,9 +7812,13 @@ "<{ entries: ", "ArrayC", "<", + "IntersectionC", + "<[", "TypeC", "<{ id: ", "StringC", + "; title: ", + "StringC", "; text: ", "BrandC", "<", @@ -7480,23 +7831,61 @@ "section": "def-common.NonEmptyStringBrand", "text": "NonEmptyStringBrand" }, - ">; }>>; }>; }>, ", - "ObservabilityAIAssistantRouteHandlerResources", - ", void, ", - "ObservabilityAIAssistantRouteCreateOptions", - ">; \"GET /internal/observability_ai_assistant/kb/user_instructions\": ", + ">; }>, ", + "PartialC", + "<{ confidence: ", + "UnionC", + "<[", + "LiteralC", + "<\"low\">, ", + "LiteralC", + "<\"medium\">, ", + "LiteralC", + "<\"high\">]>; is_correction: ", + "Type", + "; public: ", + "Type", + "; labels: ", + "RecordC", + "<", + "StringC", + ", ", + "StringC", + ">; role: ", + "UnionC", + "<[", + "LiteralC", + "<", { - "pluginId": "@kbn/server-route-repository-utils", + "pluginId": "observabilityAIAssistant", "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.ServerRoute", - "text": "ServerRoute" + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" }, - "<\"GET /internal/observability_ai_assistant/kb/user_instructions\", undefined, ", + ".AssistantSummarization>, ", + "LiteralC", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".UserEntry>, ", + "LiteralC", + "<", + { + "pluginId": "observabilityAIAssistant", + "scope": "common", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-common.KnowledgeBaseEntryRole", + "text": "KnowledgeBaseEntryRole" + }, + ".Elastic>]>; }>]>>; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", - ", { userInstructions: (", - "Instruction", - " & { public?: boolean | undefined; })[]; }, ", + ", void, ", "ObservabilityAIAssistantRouteCreateOptions", ">; \"PUT /internal/observability_ai_assistant/kb/user_instructions\": ", { @@ -7604,7 +7993,7 @@ "TypeC", "<{ body: ", "TypeC", - "<{ id: ", + "<{ title: ", "StringC", "; text: ", "BrandC", @@ -7628,13 +8017,7 @@ "LiteralC", "<\"high\">]>; is_correction: ", "Type", - "; type: ", - "UnionC", - "<[", - "LiteralC", - "<\"user_instruction\">, ", - "LiteralC", - "<\"contextual\">]>; public: ", + "; public: ", "Type", "; labels: ", "RecordC", @@ -7974,7 +8357,7 @@ "IntersectionC", "<[", "PartialC", - "<{ doc_id: ", + "<{ id: ", "StringC", "; }>, ", "TypeC", @@ -8080,7 +8463,7 @@ "IntersectionC", "<[", "PartialC", - "<{ doc_id: ", + "<{ id: ", "StringC", "; }>, ", "TypeC", @@ -9125,21 +9508,24 @@ }, { "parentPluginId": "observabilityAIAssistant", - "id": "def-common.KnowledgeBaseEntry.text", + "id": "def-common.KnowledgeBaseEntry.title", "type": "string", "tags": [], - "label": "text", + "label": "title", "description": [], + "signature": [ + "string | undefined" + ], "path": "x-pack/plugins/observability_solution/observability_ai_assistant/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "observabilityAIAssistant", - "id": "def-common.KnowledgeBaseEntry.doc_id", + "id": "def-common.KnowledgeBaseEntry.text", "type": "string", "tags": [], - "label": "doc_id", + "label": "text", "description": [], "path": "x-pack/plugins/observability_solution/observability_ai_assistant/common/types.ts", "deprecated": false, diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index d4a4ddb92a77..a5697831bc67 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant_app.mdx b/api_docs/observability_a_i_assistant_app.mdx index ada4cd32ecd4..074b93913966 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-06 +date: 2024-11-12 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 362c7695e4cf..7db6d8acbec8 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-06 +date: 2024-11-12 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 0cad810a1999..096d438580b0 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-06 +date: 2024-11-12 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 756e138bac13..49e61b7484f5 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-06 +date: 2024-11-12 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 24f7e049dc91..9c817ee1958b 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-06 +date: 2024-11-12 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 ed0dc7a0b174..d8542324ad38 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-06 +date: 2024-11-12 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 cc356c2e2b9c..5e4cdb40148c 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-06 +date: 2024-11-12 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 e6a7b1e388fc..450e68bfc2f4 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -15,13 +15,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Count | Plugins or Packages with a
public API | Number of teams | |--------------|----------|------------------------| -| 878 | 751 | 45 | +| 879 | 751 | 45 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 54167 | 240 | 40658 | 2004 | +| 54217 | 240 | 40700 | 2000 | ## Plugin Directory @@ -49,11 +49,11 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | The cloud security posture plugin | 13 | 0 | 2 | 2 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 39 | 0 | 30 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Content management app | 149 | 0 | 125 | 6 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Controls Plugin contains embeddable components intended to create a simple query interface for end users, and a powerful editing suite that allows dashboard authors to build controls | 135 | 0 | 131 | 14 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Controls Plugin contains embeddable components intended to create a simple query interface for end users, and a powerful editing suite that allows dashboard authors to build controls | 135 | 0 | 131 | 15 | | crossClusterReplication | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 0 | 0 | 0 | 0 | | customBranding | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Enables customization of Kibana | 0 | 0 | 0 | 0 | | | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 268 | 0 | 249 | 1 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 130 | 0 | 125 | 14 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 114 | 0 | 111 | 13 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 54 | 0 | 51 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3209 | 31 | 2594 | 24 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 6 | 0 | 6 | 0 | @@ -69,7 +69,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@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 | 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 | 52 | 0 | 37 | 2 | +| | [@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 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Extends embeddable plugin with more functionality | 19 | 0 | 19 | 2 | | | [@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 | @@ -103,7 +103,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) | - | 1426 | 5 | 1303 | 81 | +| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1418 | 5 | 1295 | 81 | | 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 | @@ -179,15 +179,15 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 32 | 0 | 13 | 0 | | | [@elastic/kibana-reporting-services](https://github.com/orgs/elastic/teams/kibana-reporting-services) | Kibana Screenshotting Plugin | 32 | 0 | 8 | 3 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | AI Assistant for Search | 6 | 0 | 6 | 0 | -| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | Plugin hosting shared features for connectors | 19 | 0 | 19 | 3 | +| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | Plugin hosting shared features for connectors | 7 | 0 | 7 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 18 | 0 | 10 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 18 | 0 | 18 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 11 | 0 | 7 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | Plugin to provide access to and rendering of python notebooks for use in the persistent developer console. | 10 | 0 | 10 | 1 | -| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 21 | 0 | 15 | 1 | +| | [@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) | - | 186 | 0 | 118 | 33 | +| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 188 | 0 | 120 | 33 | | | [@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 | @@ -204,7 +204,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 108 | 0 | 64 | 7 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 45 | 0 | 1 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 31 | 0 | 26 | 6 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 1 | 0 | 1 | 0 | +| telemetryCollectionXpack | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 0 | 0 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | Elastic threat intelligence helps you see if you are open to or have been subject to current or historical known threats | 30 | 0 | 14 | 4 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 226 | 1 | 182 | 17 | @@ -235,7 +235,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Registers the vega visualization. Is the elastic version of vega and vega-lite libraries. | 2 | 0 | 2 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains the vislib visualizations. These are the classical area/line/bar, gauge/goal and heatmap charts. We want to replace them with elastic-charts. | 1 | 0 | 1 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains the new xy-axis chart using the elastic-charts library, which will eventually replace the vislib xy-axis charts including bar, area, and line. | 52 | 0 | 50 | 5 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 872 | 12 | 841 | 20 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains the shared architecture among all the legacy visualizations, e.g. the visualization type registry or the visualization embeddable. | 871 | 12 | 840 | 20 | | watcher | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 0 | 0 | 0 | 0 | ## Package Directory @@ -373,7 +373,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 7 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 54 | 7 | 54 | 6 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 15 | 0 | 15 | 1 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 552 | 2 | 232 | 1 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 557 | 2 | 232 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 96 | 0 | 83 | 10 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 46 | 0 | 45 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 2 | 0 | @@ -434,7 +434,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 128 | 0 | 94 | 44 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 12 | 0 | 12 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 564 | 1 | 134 | 4 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 73 | 0 | 72 | 5 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 75 | 0 | 74 | 5 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 14 | 0 | 14 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 36 | 0 | 6 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 10 | 0 | 3 | 0 | @@ -520,7 +520,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@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) | - | 270 | 1 | 211 | 35 | +| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 277 | 1 | 217 | 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) | - | 79 | 0 | 71 | 0 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 202 | 0 | 190 | 12 | @@ -547,6 +547,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 37 | 0 | 27 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 36 | 0 | 7 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 47 | 0 | 40 | 0 | +| | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 75 | 0 | 73 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 124 | 3 | 124 | 0 | | | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 121 | 0 | 38 | 1 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 7 | 1 | 7 | 1 | @@ -560,7 +561,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 87 | 0 | 79 | 6 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 41 | 2 | 35 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 9 | 0 | 7 | 0 | -| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 116 | 0 | 115 | 0 | +| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 112 | 0 | 111 | 0 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 11 | 0 | 7 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 193 | 0 | 190 | 6 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 172 | 0 | 172 | 1 | @@ -575,7 +576,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 23 | 0 | 7 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 8 | 0 | 2 | 3 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 45 | 0 | 0 | 0 | -| | [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 140 | 0 | 139 | 0 | +| | [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 139 | 0 | 138 | 0 | | | [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 20 | 0 | 11 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 88 | 0 | 10 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 56 | 0 | 6 | 0 | @@ -650,16 +651,16 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 40 | 0 | 38 | 5 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 13 | 0 | 9 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 6 | 0 | 6 | 1 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 99 | 0 | 89 | 13 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 98 | 0 | 88 | 13 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 13 | 0 | 13 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 52 | 0 | 52 | 3 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 25 | 0 | 21 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 36 | 0 | 36 | 2 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 19 | 0 | 15 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 34 | 0 | 33 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 14 | 0 | 11 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 17 | 0 | 16 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 11 | 0 | 9 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 113 | 0 | 106 | 2 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 111 | 0 | 104 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 92 | 0 | 91 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | A component for creating resizable layouts containing a fixed width panel and a flexible panel, with support for horizontal and vertical layouts. | 18 | 0 | 5 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 3 | 0 | 3 | 0 | @@ -675,12 +676,12 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@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) | - | 3929 | 0 | 3929 | 0 | +| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 3948 | 0 | 3948 | 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 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 2 | 0 | 2 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 50 | 0 | 25 | 0 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 51 | 0 | 25 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 66 | 0 | 63 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 21 | 0 | 17 | 7 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 4 | 0 | 0 | 0 | @@ -776,7 +777,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 32 | 2 | 32 | 0 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 19 | 0 | 19 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 5 | 1 | -| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 316 | 4 | 268 | 14 | +| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 320 | 4 | 272 | 14 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 37 | 1 | 19 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 131 | 3 | 98 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | @@ -790,7 +791,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) | - | 59 | 0 | 50 | 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 | 183 | 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 | 184 | 0 | 108 | 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 | 315 | 0 | 286 | 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 f54dde9f3dcd..0b7f9c31a9ea 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-06 +date: 2024-11-12 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 fc6990b984af..206ed505ff73 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index 7df685ad6e49..bf012bba8d61 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-06 +date: 2024-11-12 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 edc9cd4ac9b8..d369f956a35e 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-06 +date: 2024-11-12 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 495773da464e..90127ece37af 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-06 +date: 2024-11-12 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 ec961837b098..fe3bdc4f656c 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-06 +date: 2024-11-12 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 81c275e80aec..2f5444d4041c 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-06 +date: 2024-11-12 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 35aff09472ec..33ff7e05af80 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-06 +date: 2024-11-12 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 ad1c236e6f57..12e54ddd2495 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-06 +date: 2024-11-12 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 1100f6c15587..3e3a002659d5 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_finder.mdx b/api_docs/saved_objects_finder.mdx index 358e480ec0b0..5d82125c05cc 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsFinder'] --- import savedObjectsFinderObj from './saved_objects_finder.devdocs.json'; diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index b8fbeb9d0401..393bb25c35ec 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-06 +date: 2024-11-12 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 9771b77adaba..fb96c0c1637c 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-06 +date: 2024-11-12 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 23bf04248700..9a86f855006d 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-06 +date: 2024-11-12 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 a18c3a9a6f79..7aa957856f6f 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-06 +date: 2024-11-12 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 752d84ce921f..ecc45f81df2a 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-06 +date: 2024-11-12 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 2eacc96fbf71..658acfa48d51 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-06 +date: 2024-11-12 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 70e09994214a..ad278f7e2714 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchAssistant'] --- import searchAssistantObj from './search_assistant.devdocs.json'; diff --git a/api_docs/search_connectors.devdocs.json b/api_docs/search_connectors.devdocs.json index ae37858d4749..2a7fc789e21b 100644 --- a/api_docs/search_connectors.devdocs.json +++ b/api_docs/search_connectors.devdocs.json @@ -5,25 +5,7 @@ "functions": [], "interfaces": [], "enums": [], - "misc": [ - { - "parentPluginId": "searchConnectors", - "id": "def-public.ConnectorDefinition", - "type": "Type", - "tags": [], - "label": "ConnectorDefinition", - "description": [], - "signature": [ - "ConnectorClientSideDefinition", - " & ", - "ConnectorServerSideDefinition" - ], - "path": "x-pack/plugins/search_connectors/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - } - ], + "misc": [], "objects": [], "setup": { "parentPluginId": "searchConnectors", @@ -45,7 +27,13 @@ "description": [], "signature": [ "() => ", - "ConnectorServerSideDefinition", + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.ConnectorServerSideDefinition", + "text": "ConnectorServerSideDefinition" + }, "[]" ], "path": "x-pack/plugins/search_connectors/public/types.ts", @@ -78,7 +66,13 @@ "description": [], "signature": [ "() => ", - "ConnectorDefinition", + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.ConnectorDefinition", + "text": "ConnectorDefinition" + }, "[]" ], "path": "x-pack/plugins/search_connectors/public/types.ts", @@ -95,152 +89,9 @@ "server": { "classes": [], "functions": [], - "interfaces": [ - { - "parentPluginId": "searchConnectors", - "id": "def-server.ConnectorServerSideDefinition", - "type": "Interface", - "tags": [], - "label": "ConnectorServerSideDefinition", - "description": [], - "path": "x-pack/plugins/search_connectors/common/connectors.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "searchConnectors", - "id": "def-server.ConnectorServerSideDefinition.categories", - "type": "Array", - "tags": [], - "label": "categories", - "description": [], - "signature": [ - "string[] | undefined" - ], - "path": "x-pack/plugins/search_connectors/common/connectors.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "searchConnectors", - "id": "def-server.ConnectorServerSideDefinition.description", - "type": "string", - "tags": [], - "label": "description", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/search_connectors/common/connectors.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "searchConnectors", - "id": "def-server.ConnectorServerSideDefinition.iconPath", - "type": "string", - "tags": [], - "label": "iconPath", - "description": [], - "path": "x-pack/plugins/search_connectors/common/connectors.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "searchConnectors", - "id": "def-server.ConnectorServerSideDefinition.isBeta", - "type": "boolean", - "tags": [], - "label": "isBeta", - "description": [], - "path": "x-pack/plugins/search_connectors/common/connectors.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "searchConnectors", - "id": "def-server.ConnectorServerSideDefinition.isNative", - "type": "boolean", - "tags": [], - "label": "isNative", - "description": [], - "path": "x-pack/plugins/search_connectors/common/connectors.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "searchConnectors", - "id": "def-server.ConnectorServerSideDefinition.isTechPreview", - "type": "CompoundType", - "tags": [], - "label": "isTechPreview", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/search_connectors/common/connectors.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "searchConnectors", - "id": "def-server.ConnectorServerSideDefinition.keywords", - "type": "Array", - "tags": [], - "label": "keywords", - "description": [], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/search_connectors/common/connectors.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "searchConnectors", - "id": "def-server.ConnectorServerSideDefinition.name", - "type": "string", - "tags": [], - "label": "name", - "description": [], - "path": "x-pack/plugins/search_connectors/common/connectors.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "searchConnectors", - "id": "def-server.ConnectorServerSideDefinition.serviceType", - "type": "string", - "tags": [], - "label": "serviceType", - "description": [], - "path": "x-pack/plugins/search_connectors/common/connectors.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - } - ], + "interfaces": [], "enums": [], - "misc": [ - { - "parentPluginId": "searchConnectors", - "id": "def-server.CONNECTOR_DEFINITIONS", - "type": "Array", - "tags": [], - "label": "CONNECTOR_DEFINITIONS", - "description": [], - "signature": [ - "ConnectorServerSideDefinition", - "[]" - ], - "path": "x-pack/plugins/search_connectors/common/connectors.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - } - ], + "misc": [], "objects": [], "setup": { "parentPluginId": "searchConnectors", @@ -262,7 +113,13 @@ "description": [], "signature": [ "() => ", - "ConnectorServerSideDefinition", + { + "pluginId": "@kbn/search-connectors", + "scope": "common", + "docId": "kibKbnSearchConnectorsPluginApi", + "section": "def-common.ConnectorServerSideDefinition", + "text": "ConnectorServerSideDefinition" + }, "[]" ], "path": "x-pack/plugins/search_connectors/server/types.ts", diff --git a/api_docs/search_connectors.mdx b/api_docs/search_connectors.mdx index 5cb60b3745c4..5c9b12c2ad9c 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchConnectors'] --- import searchConnectorsObj from './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 | |-------------------|-----------|------------------------|-----------------| -| 19 | 0 | 19 | 3 | +| 7 | 0 | 7 | 0 | ## Client @@ -31,9 +31,6 @@ Contact [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-ki ### Start -### Consts, variables and types - - ## Server ### Setup @@ -42,9 +39,3 @@ Contact [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-ki ### Start -### Interfaces - - -### Consts, variables and types - - diff --git a/api_docs/search_homepage.mdx b/api_docs/search_homepage.mdx index b2c0a5be8c6d..b19d497edcd8 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchHomepage'] --- import searchHomepageObj from './search_homepage.devdocs.json'; diff --git a/api_docs/search_indices.devdocs.json b/api_docs/search_indices.devdocs.json index 2a5d681533d1..11be05829ab5 100644 --- a/api_docs/search_indices.devdocs.json +++ b/api_docs/search_indices.devdocs.json @@ -85,7 +85,7 @@ "label": "startAppId", "description": [], "signature": [ - "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" + "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\" | \"elasticsearchIndices:createIndex\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" ], "path": "x-pack/plugins/search_indices/public/types.ts", "deprecated": false, diff --git a/api_docs/search_indices.mdx b/api_docs/search_indices.mdx index 2cbe439eb665..9f24d98efc5e 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-06 +date: 2024-11-12 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 78b171a02003..2f982d4bd9f2 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchInferenceEndpoints'] --- import searchInferenceEndpointsObj from './search_inference_endpoints.devdocs.json'; diff --git a/api_docs/search_notebooks.mdx b/api_docs/search_notebooks.mdx index 0dc1a3bb31be..9c6cc120f9d5 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchNotebooks'] --- import searchNotebooksObj from './search_notebooks.devdocs.json'; diff --git a/api_docs/search_playground.devdocs.json b/api_docs/search_playground.devdocs.json index 17d790c21d72..c097d00d40a1 100644 --- a/api_docs/search_playground.devdocs.json +++ b/api_docs/search_playground.devdocs.json @@ -4,7 +4,20 @@ "classes": [], "functions": [], "interfaces": [], - "enums": [], + "enums": [ + { + "parentPluginId": "searchPlayground", + "id": "def-public.PlaygroundPageMode", + "type": "Enum", + "tags": [], + "label": "PlaygroundPageMode", + "description": [], + "path": "x-pack/plugins/search_playground/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], "misc": [], "objects": [], "setup": { diff --git a/api_docs/search_playground.mdx b/api_docs/search_playground.mdx index 28916e9199c3..e4f76b15cc21 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchPlayground'] --- import searchPlaygroundObj from './search_playground.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 | |-------------------|-----------|------------------------|-----------------| -| 21 | 0 | 15 | 1 | +| 22 | 0 | 16 | 1 | ## Client @@ -31,6 +31,9 @@ Contact [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-ki ### Start +### Enums + + ## Server ### Setup diff --git a/api_docs/security.devdocs.json b/api_docs/security.devdocs.json index 18274d63075c..06d005330608 100644 --- a/api_docs/security.devdocs.json +++ b/api_docs/security.devdocs.json @@ -6501,6 +6501,18 @@ "plugin": "entityManager", "path": "x-pack/plugins/entity_manager/server/routes/enablement/disable.ts" }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/server/lib/helpers/get_random_sampler/index.ts" + }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/server/routes/agent_keys/get_agent_keys_privileges.ts" + }, + { + "plugin": "apm", + "path": "x-pack/plugins/observability_solution/apm/server/routes/fleet/is_superuser.ts" + }, { "plugin": "serverlessSearch", "path": "x-pack/plugins/serverless_search/server/routes/api_key_routes.ts" @@ -6521,18 +6533,6 @@ "plugin": "upgradeAssistant", "path": "x-pack/plugins/upgrade_assistant/server/lib/reindexing/credential_store.ts" }, - { - "plugin": "apm", - "path": "x-pack/plugins/observability_solution/apm/server/lib/helpers/get_random_sampler/index.ts" - }, - { - "plugin": "apm", - "path": "x-pack/plugins/observability_solution/apm/server/routes/agent_keys/get_agent_keys_privileges.ts" - }, - { - "plugin": "apm", - "path": "x-pack/plugins/observability_solution/apm/server/routes/fleet/is_superuser.ts" - }, { "plugin": "synthetics", "path": "x-pack/plugins/observability_solution/synthetics/server/synthetics_service/get_api_key.ts" diff --git a/api_docs/security.mdx b/api_docs/security.mdx index 0dfe337c1261..f2a9ff6f5a85 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-06 +date: 2024-11-12 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 d155268affcd..608baf2669df 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -2778,6 +2778,29 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "securitySolution", + "id": "def-server.SecuritySolutionApiRequestHandlerContext.getDataViewsService", + "type": "Function", + "tags": [], + "label": "getDataViewsService", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewsService", + "text": "DataViewsService" + } + ], + "path": "x-pack/plugins/security_solution/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "securitySolution", "id": "def-server.SecuritySolutionApiRequestHandlerContext.getExceptionListClient", @@ -2889,14 +2912,37 @@ }, { "parentPluginId": "securitySolution", - "id": "def-server.SecuritySolutionApiRequestHandlerContext.getSiemMigrationsClient", + "id": "def-server.SecuritySolutionApiRequestHandlerContext.getSiemRuleMigrationsClient", "type": "Function", "tags": [], - "label": "getSiemMigrationsClient", + "label": "getSiemRuleMigrationsClient", "description": [], "signature": [ "() => ", - "SiemMigrationsClient" + "SiemRuleMigrationsClient" + ], + "path": "x-pack/plugins/security_solution/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "securitySolution", + "id": "def-server.SecuritySolutionApiRequestHandlerContext.getInferenceClient", + "type": "Function", + "tags": [], + "label": "getInferenceClient", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "inference", + "scope": "server", + "docId": "kibInferencePluginApi", + "section": "def-server.InferenceClient", + "text": "InferenceClient" + } ], "path": "x-pack/plugins/security_solution/server/types.ts", "deprecated": false, diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index dc1b9a3d66c9..8c458c5dd5c9 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-06 +date: 2024-11-12 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 | |-------------------|-----------|------------------------|-----------------| -| 186 | 0 | 118 | 33 | +| 188 | 0 | 120 | 33 | ## Client diff --git a/api_docs/security_solution_ess.mdx b/api_docs/security_solution_ess.mdx index c253b80d8b91..09498b8b4441 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-06 +date: 2024-11-12 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 be48339ece39..e85832e528bd 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-06 +date: 2024-11-12 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 d1db5c8c6efd..834b2849bf4f 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-06 +date: 2024-11-12 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 2f0e3bd1df6f..ab9d0dafee7d 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-06 +date: 2024-11-12 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 6e16bebce8de..42e3a4a3621d 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-06 +date: 2024-11-12 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 a43fc1a69310..0fe1099b6475 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-06 +date: 2024-11-12 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 a09c4d37729a..9a754c7f4216 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/slo.mdx b/api_docs/slo.mdx index 920a755b4094..25f86f6999c9 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'slo'] --- import sloObj from './slo.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index 81913419ea12..0db83bcf54f2 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-06 +date: 2024-11-12 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 d5b2cb390f07..b0cd89257784 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-06 +date: 2024-11-12 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 301e0da105ce..ffe989d464af 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-06 +date: 2024-11-12 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 43263b1cf927..5c1c4923420b 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index d33fea0e5a92..3c670603eb89 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-06 +date: 2024-11-12 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 d897dc412ddd..43819592c035 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-06 +date: 2024-11-12 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 a7bb5c57965e..eca438724845 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-06 +date: 2024-11-12 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 ab641ee07336..1c5b7f448713 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-06 +date: 2024-11-12 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 b44f8bdf3a61..b2ad8e21aff3 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.devdocs.json b/api_docs/timelines.devdocs.json index 7b207604ff70..8b9294349ef3 100644 --- a/api_docs/timelines.devdocs.json +++ b/api_docs/timelines.devdocs.json @@ -3808,14 +3808,6 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/timelines/components/timeline/data_providers/provider_item_badge.tsx" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/helpers.ts" diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index 534feb8f261b..fbacc1e90a62 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-06 +date: 2024-11-12 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 f140bf24539e..291701282c81 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-06 +date: 2024-11-12 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 5b28484e4bf4..fffd0501602d 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-06 +date: 2024-11-12 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 1ed25f057a02..92773d148739 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-06 +date: 2024-11-12 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 516401a39a67..1222419d87c9 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-06 +date: 2024-11-12 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 463f7e2fb454..6613e34f4365 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedDocViewer'] --- import unifiedDocViewerObj from './unified_doc_viewer.devdocs.json'; diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index 83c7f132f7d2..14165a4707ea 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 2b2f0de1fc9c..176451a11b83 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-06 +date: 2024-11-12 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 3031aa5aad76..7f85dc30a86d 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-06 +date: 2024-11-12 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 4194639a9ec9..868b1e28155d 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-06 +date: 2024-11-12 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 236049250392..45c1fcb5ea0b 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-06 +date: 2024-11-12 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 af7c54eba79e..fbd8706e92a6 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-06 +date: 2024-11-12 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 00a283e192b5..b623525fb2cf 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-06 +date: 2024-11-12 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 6f59dff99098..2860a5adf69c 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-06 +date: 2024-11-12 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 04519c6de8a9..717b780a8b2b 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-06 +date: 2024-11-12 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 220a9dc753ca..e15ce6607d5e 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-06 +date: 2024-11-12 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 93a2b93d3657..cdc9a04b9baa 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-06 +date: 2024-11-12 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 d33bdf75f78b..dae1914194af 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-06 +date: 2024-11-12 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 1ef84aca7478..cfa2d3463f78 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-06 +date: 2024-11-12 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 178c2d2f4191..4baff6787751 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-06 +date: 2024-11-12 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 d2955034fa37..d21887d0ab6a 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-06 +date: 2024-11-12 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 2ab7000de0c5..11f32e53b40e 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-06 +date: 2024-11-12 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 15efbe2e7872..bb4c1e7c59b1 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-06 +date: 2024-11-12 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 b3a0a1f57513..d2d15673ef45 100644 --- a/api_docs/visualizations.devdocs.json +++ b/api_docs/visualizations.devdocs.json @@ -336,20 +336,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "visualizations", - "id": "def-public.BaseVisType.suppressWarnings", - "type": "Function", - "tags": [], - "label": "suppressWarnings", - "description": [], - "signature": [ - "(() => boolean) | undefined" - ], - "path": "src/plugins/visualizations/public/vis_types/base_vis_type.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "visualizations", "id": "def-public.BaseVisType.hasPartialRows", @@ -6984,7 +6970,15 @@ "section": "def-public.PublishingSubject", "text": "PublishingSubject" }, - "; lockHoverActions: (lock: boolean) => void; disableTriggers: boolean; timeRange$: ", + "; lockHoverActions: (lock: boolean) => void; disableTriggers: boolean; savedObjectId: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; timeRange$: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -7096,15 +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; savedObjectId: ", - { - "pluginId": "@kbn/presentation-publishing", - "scope": "public", - "docId": "kibKbnPresentationPublishingPluginApi", - "section": "def-public.PublishingSubject", - "text": "PublishingSubject" - }, - "; render: (domNode: HTMLElement) => Promise; getEditHref: () => Promise; reload: () => Promise; updateInput: (changes: Partial<", + " | 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; reload: () => Promise; updateInput: (changes: Partial<", { "pluginId": "visualizations", "scope": "public", diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 754773122575..78840e906c6a 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-06 +date: 2024-11-12 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 872 | 12 | 841 | 20 | +| 871 | 12 | 840 | 20 | ## Client diff --git a/dev_docs/nav-kibana-dev.docnav.json b/dev_docs/nav-kibana-dev.docnav.json index 289593aaf159..141af7984adf 100644 --- a/dev_docs/nav-kibana-dev.docnav.json +++ b/dev_docs/nav-kibana-dev.docnav.json @@ -624,9 +624,6 @@ { "id": "kibTelemetryCollectionManagerPluginApi" }, - { - "id": "kibTelemetryCollectionXpackPluginApi" - }, { "id": "kibTelemetryManagementSectionPluginApi" }, diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index 22d5aaa2877c..dccad6f918c6 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -11,6 +11,7 @@ Review important information about the {kib} 8.x releases. * <> +* <> * <> * <> * <> @@ -93,7 +94,7 @@ Deprecated functionality does not have an immediate impact on your application, you make the necessary updates after you upgrade to 8.16.0. [discrete] -* The Logs Stream is now hidden by default in favor of the Logs Explorer app. +.The Logs Stream is now hidden by default in favor of the Logs Explorer app. [%collapsible] ==== *Details* + @@ -104,7 +105,7 @@ You can still show the Logs Stream app again by navigating to Stack Management > ==== [discrete] -* Deprecates the Observability AI Assistant specific advanced setting `observability:aiAssistantLogsIndexPattern`. +.Deprecates the Observability AI Assistant specific advanced setting `observability:aiAssistantLogsIndexPattern`. [%collapsible] ==== *Details* + @@ -430,6 +431,33 @@ Management:: * Fixes the pagination of the source documents data grid in Transforms ({kibana-pull}196119[#196119]). * Fixes autocomplete suggestions after a comma in Console ({kibana-pull}189656[#189656]). +[[release-notes-8.15.4]] +== {kib} 8.15.4 + +The 8.15.4 release includes the following bug fixes. + +[float] +[[fixes-v8.15.4]] +=== Bug fixes +Dashboards and visualizations:: +* Fixes incomplete string escaping and encoding in *TSVB* ({kibana-pull}196248[#196248]). +* Adds scroll margin to panels ({kibana-pull}193430[#193430]). +* Fixes an issue where label truncation in heat map legends was not working properly in *Lens* ({kibana-pull}195928[#195928]). +Discover:: +* Fixes the width for saved object Type column ({kibana-pull}194388[#194388]). +Elastic Observability solution:: +* Changes the slice outcome from bad to good whenever there is no data during the slice window ({kibana-pull}196942[#196942]). +Elastic Search solution:: +* Fixes a bug with the {ref}/es-connectors-network-drive.html[Network Drive connector] where advanced configuration fields were not displayed for CSV file role mappings with `Drive Type: Linux` selected ({kibana-pull}195567[#195567]). +Elastic Security solution:: +For the Elastic Security 8.15.4 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_]. +Kibana platform:: +* Fixes an issue causing the wrong date to show in the header of a report when generated from a relative date ({kibana-pull}197027[#197027]). +* Fixes an issue with the export options for PNG/PDF reports in a dashboard ({kibana-pull}192530[#192530]). +Machine Learning:: +* Fixes an issue preventing Anomaly swim lane panels from updating on query changes ({kibana-pull}195090[#195090]). +Management:: +* Fixes the pagination of the source documents data grid in Transforms ({kibana-pull}196119[#196119]). [[release-notes-8.15.3]] == {kib} 8.15.3 @@ -456,7 +484,6 @@ Elastic Security solution:: For the Elastic Security 8.15.3 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_]. Kibana security:: * Automatic Import no longer asks the LLM to map fields to reserved ECS fields ({kibana-pull}195168[#195168]). -* Automatic Import no longer returns an "Invalid ECS field" message when the ECS mapping slightly differs from the expected format. For example `date_format` instead of `date_formats` ({kibana-pull}195167[#195167]). * Fixes an issue that was causing the Grok processor to return non-ECS compatible fields when processing structured or unstructured syslog samples in Automatic Import ({kibana-pull}194727[#194727]). * Fixes the integrationName when uploading a new version of an existing integration using a ZIP upload ({kibana-pull}194298[#194298]). * Fixes a bug that caused the Deploy step of Automatic Import to fail after a pipeline was edited and saved ({kibana-pull}194203[#194203]). diff --git a/docs/api/synthetics/monitors/delete-monitor-api.asciidoc b/docs/api/synthetics/monitors/delete-monitor-api.asciidoc index 70861fcd60a3..74798b40830b 100644 --- a/docs/api/synthetics/monitors/delete-monitor-api.asciidoc +++ b/docs/api/synthetics/monitors/delete-monitor-api.asciidoc @@ -17,9 +17,6 @@ Deletes one or more monitors from the Synthetics app. You must have `all` privileges for the *Synthetics* feature in the *{observability}* section of the <>. -You must have `all` privileges for the *Synthetics* feature in the *{observability}* section of the -<>. - [[delete-monitor-api-path-params]] === {api-path-parms-title} @@ -27,7 +24,6 @@ You must have `all` privileges for the *Synthetics* feature in the *{observabili `config_id`:: (Required, string) The ID of the monitor that you want to delete. - Here is an example of a DELETE request to delete a monitor by ID: [source,sh] @@ -37,7 +33,7 @@ DELETE /api/synthetics/monitors/monitor1-id ==== Bulk Delete Monitors -You can delete multiple monitors by sending a list of config ids to a DELETE request to the `/api/synthetics/monitors` endpoint. +You can delete multiple monitors by sending a list of config ids to a POST request to the `/api/synthetics/monitors/_bulk_delete` endpoint. [[monitors-delete-request-body]] @@ -49,11 +45,11 @@ The request body should contain an array of monitors IDs that you want to delete (Required, array of strings) An array of monitor IDs to delete. -Here is an example of a DELETE request to delete a list of monitors by ID: +Here is an example of a POST request to delete a list of monitors by ID: [source,sh] -------------------------------------------------- -DELETE /api/synthetics/monitors +POST /api/synthetics/monitors/_bulk_delete { "ids": [ "monitor1-id", diff --git a/docs/api/synthetics/params/delete-param.asciidoc b/docs/api/synthetics/params/delete-param.asciidoc index 4c7d7911ec18..031a47501a8a 100644 --- a/docs/api/synthetics/params/delete-param.asciidoc +++ b/docs/api/synthetics/params/delete-param.asciidoc @@ -8,9 +8,9 @@ Deletes one or more parameters from the Synthetics app. === {api-request-title} -`DELETE :/api/synthetics/params` +`DELETE :/api/synthetics/params/` -`DELETE :/s//api/synthetics/params` +`DELETE :/s//api/synthetics/params/` === {api-prereq-title} @@ -20,26 +20,19 @@ You must have `all` privileges for the *Synthetics* feature in the *{observabili You must have `all` privileges for the *Synthetics* feature in the *{observability}* section of the <>. -[[parameters-delete-request-body]] -==== Request Body +[[parameters-delete-path-param]] +==== Path Parameters The request body should contain an array of parameter IDs that you want to delete. -`ids`:: -(Required, array of strings) An array of parameter IDs to delete. +`param_id`:: +(Required, string) An id of parameter to delete. - -Here is an example of a DELETE request to delete a list of parameters by ID: +Here is an example of a DELETE request to delete a parameter by its ID: [source,sh] -------------------------------------------------- -DELETE /api/synthetics/params -{ - "ids": [ - "param1-id", - "param2-id" - ] -} +DELETE /api/synthetics/params/param_id1 -------------------------------------------------- [[parameters-delete-response-example]] @@ -58,10 +51,21 @@ Here's an example response for deleting multiple parameters: { "id": "param1-id", "deleted": true - }, - { - "id": "param2-id", - "deleted": true } ] --------------------------------------------------- \ No newline at end of file +-------------------------------------------------- + +==== Bulk delete parameters +To delete multiple parameters, you can send a POST request to `/api/synthetics/params/_bulk_delete` with an array of parameter IDs to delete via body. + +Here is an example of a POST request to delete multiple parameters: + +[source,sh] +-------------------------------------------------- +POST /api/synthetics/params/_bulk_delete +{ + "ids": ["param1-id", "param2-id"] +} +-------------------------------------------------- + + diff --git a/docs/canvas/canvas-expression-lifecycle.asciidoc b/docs/canvas/canvas-expression-lifecycle.asciidoc deleted file mode 100644 index a20181c4b380..000000000000 --- a/docs/canvas/canvas-expression-lifecycle.asciidoc +++ /dev/null @@ -1,263 +0,0 @@ -[role="xpack"] -[[canvas-expression-lifecycle]] -== Canvas expression lifecycle - -Elements in Canvas are all created using an *expression language* that defines how to retrieve, manipulate, and ultimately visualize data. The goal is to allow you to do most of what you need without understanding the *expression language*, but learning how it works unlocks a lot of Canvas's power. - - -[[canvas-expressions-always-start-with-a-function]] -=== Expressions always start with a function - -Expressions simply execute <> in a specific order, which produce some output value. That output can then be inserted into another function, and another after that, until it produces the output you need. - -To use demo dataset available in Canvas to produce a table, run the following expression: - -[source,text] ----- -/* Simple demo table */ -filters -| demodata -| table -| render ----- - -This expression starts out with the <> function, which provides the value of any time filters or dropdown filters in the workpad. This is then inserted into <>, a function that returns exactly what you expect, demo data. Because the <> function receives the filter information from the <> function before it, it applies those filters to reduce the set of data it returns. We call the output from the previous function _context_. - -The filtered <> becomes the _context_ of the next function, <>, which creates a table visualization from this data set. The <> function isn’t strictly required, but by being explicit, you have the option of providing arguments to control things like the font used in the table. The output of the <> function becomes the _context_ of the <> function. Like the <>, the <> function isn’t required either, but it allows access to other arguments, such as styling the border of the element or injecting custom CSS. - -It is possible to add comments to the expression by starting them with a `//` sequence or by using `/*` and `*/` to enclose multi-line comments. - -[[canvas-function-arguments]] -=== Function arguments - -Let’s look at another expression, which uses the same <> function, but instead produces a pie chart. - -image::images/canvas-functions-can-take-arguments-pie-chart.png[Pie chart showing output of demodata function] -[source,text] ----- -filters -| demodata -| pointseries color="state" size="max(price)" -| pie -| render ----- - -To produce a filtered set of random data, the expression uses the <> and <> functions. This time, however, the output becomes the context for the <> function, which is a way to aggregate your data, similar to how Elasticsearch works, but more generalized. In this case, the data is split up using the `color` and `size` dimensions, using arguments on the <> function. Each unique value in the state column will have an associated size value, which in this case, will be the maximum value of the price column. - -If the expression stopped there, it would produce a `pointseries` data type as the output of this expression. But instead of looking at the raw values, the result is inserted into the <> function, which will produce an output that will render a pie visualization. And just like before, this is inserted into the <> function, which is useful for its arguments. - -The end result is a simple pie chart that uses the default color palette, but the <> function can take additional arguments that control how it gets rendered. For example, you can provide a `hole` argument to turn your pie chart into a donut chart by changing the expression to: - - -image::images/canvas-functions-can-take-arguments-donut-chart.png[Alternative output as donut chart] -[source,text] ----- -filters -| demodata -| pointseries color="state" size="max(price)" -| pie hole=50 -| render ----- - - -[[canvas-aliases-and-unnamed-arguments]] -=== Aliases and unnamed arguments - -Argument definitions have one canonical name, which is always provided in the underlying code. When argument definitions are used in an expression, they often include aliases that make them easier or faster to type. - -For example, the <> function has 2 arguments: - -* `expression` - Produces a calculated value. -* `name` - The name of column. - -The `expression` argument includes some aliases, namely `exp`, `fn`, and `function`. That means that you can use any of those four options to provide that argument’s value. - -So `mapColumn name=newColumn fn={string example}` is equal to `mapColumn name=newColumn expression={string example}`. - -There’s also a special type of alias which allows you to leave off the argument’s name entirely. The alias for this is an underscore, which indicates that the argument is an _unnamed_ argument and can be provided without explicitly naming it in the expression. The `name` argument here uses the _unnamed_ alias, which means that you can further simplify our example to `mapColumn newColumn fn={string example}`. - -NOTE: There can only be one _unnamed_ argument for each function. - - -[[canvas-change-your-expression-change-your-output]] -=== Change your expression, change your output -You can substitute one function for another to change the output. For example, you could change the visualization by swapping out the <> function for another renderer, a function that returns a `render` data type. - -Let’s change that last pie chart into a bubble chart by replacing the <> function with the <> function. This is possible because both functions can accept a `pointseries` data type as their _context_. Switching the functions will work, but it won’t produce a useful visualization on its own since you don’t have the x-axis and y-axis defined. You will also need to modify the <> function to change its output. In this case, you can change the `size` argument to `y`, so the maximum price values are plotted on the y-axis, and add an `x` argument using the `@timestamp` field in the data to plot those values over time. This leaves you with the following expression and produces a bubble chart showing the max price of each state over time: - -image::images/canvas-change-your-expression-chart.png[Bubble Chart, with price along x axis, and time along y axis] -[source,text] ----- -filters -| demodata -| pointseries color="state" y="max(price)" x="@timestamp" -| plot -| render ----- - -Similar to the <> function, the <> function takes arguments that control the design elements of the visualization. As one example, passing a `legend` argument with a value of `false` to the function will hide the legend on the chart. - -image::images/canvas-change-your-expression-chart-no-legend.png[Bubble Chart Without Legend] -[source,text,subs=+quotes] ----- -filters -| demodata -| pointseries color="state" y="max(price)" x="@timestamp" -| plot *legend=false* -| render ----- - - -[[canvas-fetch-and-manipulate-data]] -=== Fetch and manipulate data -So far, you have only seen expressions as a way to produce visualizations, but that’s not really what’s happening. Expressions only produce data, which is then used to create something, which in the case of Canvas, means rendering an element. An element can be a visualization, driven by data, but it can also be something much simpler, like a static image. Either way, an expression is used to produce an output that is used to render the desired result. For example, here’s an expression that shows an image: - -[source,text] ----- -image dataurl=https://placekitten.com/160/160 mode="cover" ----- - -But as mentioned, this doesn’t actually _render that image_, but instead it _produces some output that can be used to render that image_. That’s an important distinction, and you can see the actual output by adding in the render function and telling it to produce debug output. For example: - -[source,text] ----- -image dataurl=https://placekitten.com/160/160 mode="cover" -| render as=debug ----- - -The follow appears as JSON output: - -[source,JSON] ----- -{ - "type": "image", - "mode": "cover", - "dataurl": "https://placekitten.com/160/160" -} ----- - -NOTE: You may need to expand the element’s size to see the whole output. - -Canvas uses this output’s data type to map to a specific renderer and passes the entire output into it. It’s up to the image render function to produce an image on the workpad’s page. In this case, the expression produces some JSON output, but expressions can also produce other, simpler data, like a string or a number. Typically, useful results use JSON. - -Canvas uses the output to render an element, but other applications can use expressions to do pretty much anything. As stated previously, expressions simply execute functions, and the functions are all written in Javascript. That means if you can do something in Javascript, you can do it with an expression. - -This can include: - -* Sending emails -* Sending notifications -* Reading from a file -* Writing to a file -* Controlling devices with WebUSB or Web Bluetooth -* Consuming external APIs - -If your Javascript works in the environment where the code will run, such as in Node.js or in a browser, you can do it with an expression. - -[[canvas-expressions-compose-functions-with-subexpressions]] -=== Compose functions with sub-expressions - -You may have noticed another syntax in examples from other sections, namely expressions inside of curly brackets. These are called sub-expressions, and they can be used to provide a calculated value to another expression, instead of just a static one. - -A simple example of this is when you upload your own images to a Canvas workpad. That upload becomes an asset, and that asset can be retrieved using the `asset` function. Usually you’ll just do this from the UI, adding an image element to the page and uploading your image from the control in the sidebar, or picking an existing asset from there as well. In both cases, the system will consume that asset via the `asset` function, and you’ll end up with an expression similar to this: - -[source,text] ----- -image dataurl={asset 3cb3ec3a-84d7-48fa-8709-274ad5cc9e0b} ----- - -Sub-expressions are executed before the function that uses them is executed. In this case, `asset` will be run first, it will produce a value, the base64-encoded value of the image and that value will be used as the value for the `dataurl` argument in the <> function. After the asset function executes, you will get the following output: - -[source,text] ----- -image dataurl="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0" ----- - -Since all of the sub-expressions are now resolved into actual values, the <> function can be executed to produce its JSON output, just as it’s explained previously. In the case of images, the ability to nest sub-expressions is particularly useful to show one of several images conditionally. For example, you could swap between two images based on some calculated value by mixing in the <> function, like in this example expression: - -[source,text] ----- -demodata -| image dataurl={ - if condition={getCell price | gte 100} - then={asset "asset-3cb3ec3a-84d7-48fa-8709-274ad5cc9e0b"} - else={asset "asset-cbc11a1f-8f25-4163-94b4-2c3a060192e7"} -} ----- - -NOTE: The examples in this section can’t be copy and pasted directly, since the values used throughout will not exist in your workpad. - -Here, the expression to use for the value of the `condition` argument, `getCell price | gte 100`, runs first since it is nested deeper. - -The expression does the following: - -* Retrieves the value from the *price* column in the first row of the `demodata` data table -* Inputs the value to the `gte` function -* Compares the value to `100` -* Returns `true` if the value is 100 or greater, and `false` if the value is 100 or less - -That boolean value becomes the value for the `condition` argument. The output from the `then` expression is used as the output when `condition` is `true`. The output from the `else` expression is used when `condition` is false. In both cases, a base64-encoded image will be returned, and one of the two images will be displayed. - -You might be wondering how the <> function in the sub-expression accessed the data from the <> function, even though <> was not being directly inserted into <>. The answer is simple, but important to understand. When nested sub-expressions are executed, they automatically receive the same _context_, or output of the previous function that its parent function receives. In this specific expression, demodata’s data table is automatically provided to the nested expression’s `getCell` function, which allows that expression to pull out a value and compare it to another value. - -The passing of the _context_ is automatic, and it happens no matter how deeply you nest your sub-expressions. To demonstrate this, let’s modify the expression slightly to compare the value of the price against multiple conditions using the <> function. - -[source,text] ----- -demodata -| image dataurl={ - if condition={getCell price | all {gte 100} {neq 105}} - then={asset 3cb3ec3a-84d7-48fa-8709-274ad5cc9e0b} - else={asset cbc11a1f-8f25-4163-94b4-2c3a060192e7} -} ----- - -This time, `getCell price` is run, and the result is passed into the next function as the context. Then, each sub-expression of the <> function is run, with the context given to their parent, which in this case is the result of `getCell price`. If `all` of these sub-expressions evaluate to `true`, then the `if` condition argument will be true. - -Sub-expressions can seem a little foreign, especially if you aren’t a developer, but they’re worth getting familiar with, since they provide a ton of power and flexibility. Since you can nest any expression you want, you can also use this behavior to mix data from multiple indices, or even data from multiple sources. As an example, you could query an API for a value to use as part of the query provided to <>. - -This whole section is really just scratching the surface, but hopefully after reading it, you at least understand how to read expressions and make sense of what they are doing. With a little practice, you’ll get the hang of mixing _context_ and sub-expressions together to turn any input into your desired output. - -[[canvas-handling-context-and-argument-types]] -=== Handling context and argument types -If you look through the <>, you may notice that all of them define what a function accepts and what it returns. Additionally, every argument includes a type property that specifies the kind of data that can be used. These two types of values are actually the same, and can be used as a guide for how to deal with piping to other functions and using subexpressions for argument values. - -To explain how this works, consider the following expression from the previous section: - -[source,text] ----- -image dataurl={asset 3cb3ec3a-84d7-48fa-8709-274ad5cc9e0b} ----- - -If you <> for the `image` function, you’ll see that it accepts the `null` data type and returns an `image` data type. Accepting `null` effectively means that it does not use context at all, so if you insert anything to `image`, the value that was produced previously will be ignored. When the function executes, it will produce an `image` output, which is simply an object of type `image` that contains the information required to render an image. - -NOTE: The function does not render an image itself. - -As explained in the "<>" section, the output of an expression is just data. So the `image` type here is just a specific shape of data, not an actual image. - -Next, let’s take a look at the `asset` function. Like `image`, it accepts `null`, but it returns something different, a `string` in this case. Because `asset` will produce a string, its output can be used as the input for any function or argument that accepts a string. - -<> for the `dataurl` argument, its type is `string`, meaning it will accept any kind of string. There are some rules about the value of the string that the function itself enforces, but as far as the interpreter is concerned, that expression is valid because the argument accepts a string and the output of `asset` is a string. - -The interpreter also attempts to cast some input types into others, which allows you to use a string input even when the function or argument calls for a number. Keep in mind that it’s not able to convert any string value, but if the string is a number, it can easily be cast into a `number` type. Take the following expression for example: - -[source,text] ----- -string "0.4" -| revealImage image={asset asset-06511b39-ec44-408a-a5f3-abe2da44a426} ----- - -If you <> for the `revealImage` function, you’ll see that it accepts a `number` but the `string` function returns a `string` type. In this case, because the string value is a number, it can be converted into a `number` type and used without you having to do anything else. - -Most `primitive` types can be converted automatically, as you might expect. You just saw that a `string` can be cast into a `number`, but you can also pretty easily cast things into `boolean` too, and you can cast anything to `null`. - -There are other useful type casting options available. For example, something of type `datatable` can be cast to a type `pointseries` simply by only preserving specific columns from the data (namely x, y, size, color, and text). This allows you to treat your source data, which is generally of type `datatable`, like a `pointseries` type simply by convention. - -You can fetch data from Elasticsearch using `essql`, which allows you to aggregate the data, provide a custom name for the value, and insert that data directly to another function that only accepts `pointseries` even though `essql` will output a `datatable` type. This makes the following example expression valid: - -[source,text] ----- -essql "SELECT user AS x, sum(cost) AS y FROM index GROUP BY user" -| plot ----- - -In the docs you can see that `essql` returns a `datatable` type, but `plot` expects a `pointseries` context. This works because the `datatable` output will have the columns `x` and `y` as a result of using `AS` in the sql statement to name them. Because the data follows the convention of the `pointseries` data type, casting it into `pointseries` is possible, and it can be passed directly to `plot` as a result. diff --git a/docs/canvas/canvas-tutorial.asciidoc b/docs/canvas/canvas-tutorial.asciidoc index 5016dbec88aa..666d8885c288 100644 --- a/docs/canvas/canvas-tutorial.asciidoc +++ b/docs/canvas/canvas-tutorial.asciidoc @@ -9,15 +9,11 @@ To familiarize yourself with *Canvas*, add the Sample eCommerce orders data, the To create a workpad of the eCommerce store data, add the data set, then create the workpad. -. On the home page, click *Try sample data*. +. <>. -. Click *Other sample data sets*. +. Go to **Canvas** using the navigation menu or the <>. -. On the *Sample eCommerce orders* card, click *Add data*. - -. Open the main menu, then click *Canvas*. - -. On the *Canvas workpads* page, click *Create workpad*. +. Select *Create workpad*. [float] === Customize your workpad with images diff --git a/docs/concepts/data-views.asciidoc b/docs/concepts/data-views.asciidoc index 2eba42aed305..2a260e611a06 100644 --- a/docs/concepts/data-views.asciidoc +++ b/docs/concepts/data-views.asciidoc @@ -168,7 +168,7 @@ and field popularity data. Deleting a {data-source} does not remove any indices WARNING: Deleting a {data-source} breaks all visualizations, saved searches, and other saved objects that reference the data view. -. Open the main menu, and then click *Stack Management > Data Views*. +. Go to the **Data Views** management page using the navigation menu or the <>. . Find the {data-source} that you want to delete, and then click image:management/index-patterns/images/delete.png[Delete icon] in the *Actions* column. diff --git a/docs/concepts/esql.asciidoc b/docs/concepts/esql.asciidoc index 0390f9f6e2bc..a3a091a4c6d0 100644 --- a/docs/concepts/esql.asciidoc +++ b/docs/concepts/esql.asciidoc @@ -8,15 +8,12 @@ Based on the query, Lens suggestions in Discover create a visualization of the q {esql} comes with its own dedicated {esql} Compute Engine for greater efficiency. With one query you can search, aggregate, calculate and perform data transformations without leaving **Discover**. Write your query directly in **Discover** or use the **Dev Tools** with the {ref}/esql-rest.html[{esql} API]. -Here's how to use {esql} in the data view selector in **Discover**: +You can switch to the ES|QL mode of Discover from the application menu bar. -[role="screenshot"] -image:images/esql-data-view-menu.png[An image of the Discover UI where users can access the {esql} feature, width=30%, align="center"] - -{esql} also features in-app help, so you can get started faster and don't have to leave the application to check syntax. +{esql} also features in-app help and suggestions, so you can get started faster and don't have to leave the application to check syntax. [role="screenshot"] -image:images/esql-in-app-help.png[An image of the Discover UI where users can browse the in-app help] +image:images/esql-in-app-help.png[The ES|QL syntax reference and the autocomplete menu] You can also use ES|QL queries to create panels on your dashboards, create enrich policies, and create alerting rules. diff --git a/docs/concepts/images/esql-in-app-help.png b/docs/concepts/images/esql-in-app-help.png index 5f00248c10af..00db2cf8e50c 100644 Binary files a/docs/concepts/images/esql-in-app-help.png and b/docs/concepts/images/esql-in-app-help.png differ diff --git a/docs/dev-tools/grokdebugger/index.asciidoc b/docs/dev-tools/grokdebugger/index.asciidoc index 6a809c13fcb9..0932df0c7abf 100644 --- a/docs/dev-tools/grokdebugger/index.asciidoc +++ b/docs/dev-tools/grokdebugger/index.asciidoc @@ -36,7 +36,8 @@ is automatically enabled in {kib}. NOTE: If you're using {stack-security-features}, you must have the `manage_pipeline` permission to use the Grok Debugger. -. Open the main menu, click *Dev Tools*, then click *Grok Debugger*. +. Find the *Grok Debugger* by navigating to the *Developer tools* page using the +navigation menu or the <>. . In *Sample Data*, enter a message that is representative of the data that you want to parse. For example: + diff --git a/docs/dev-tools/painlesslab/index.asciidoc b/docs/dev-tools/painlesslab/index.asciidoc index 387c0522dd1c..84aa13b4590c 100644 --- a/docs/dev-tools/painlesslab/index.asciidoc +++ b/docs/dev-tools/painlesslab/index.asciidoc @@ -12,7 +12,8 @@ process {ref}/docs-reindex.html[reindexed data], define complex <>, and work with data in other contexts. -To get started, open the main menu, click *Dev Tools*, and then click *Painless Lab*. +Find *Painless Lab* by navigating to the *Developer tools* page using the +navigation menu or the <>. [role="screenshot"] image::dev-tools/painlesslab/images/painless-lab.png[Painless Lab] diff --git a/docs/dev-tools/searchprofiler/index.asciidoc b/docs/dev-tools/searchprofiler/index.asciidoc index c323427318d5..7ce6e9fa48b3 100644 --- a/docs/dev-tools/searchprofiler/index.asciidoc +++ b/docs/dev-tools/searchprofiler/index.asciidoc @@ -14,9 +14,8 @@ poorly performing queries much faster. [[search-profiler-getting-started]] === Get started -*{searchprofiler}* is automatically enabled in {kib}. Open the main menu, -click *Dev Tools*, and then click *{searchprofiler}* -to get started. +. Find the *{searchprofiler}* by navigating to the *Developer tools* page using the +navigation menu or the <>. *{searchprofiler}* displays the names of the indices searched, the shards in each index, and how long it took for the query to complete. To try it out, replace the default `match_all` query diff --git a/docs/developer/getting-started/sample-data.asciidoc b/docs/developer/getting-started/sample-data.asciidoc index 2454c9d8a614..a932db91c037 100644 --- a/docs/developer/getting-started/sample-data.asciidoc +++ b/docs/developer/getting-started/sample-data.asciidoc @@ -8,7 +8,7 @@ There are a couple ways to easily get data ingested into {es}. The easiest is to install one or more of our available sample data packages. If you have no data, you should be prompted to install when running {kib} for the first time. You can also access and install the sample data packages -by going to the home page and clicking "add sample data". +by going to the **Integrations** page and selecting **Sample data**. [discrete] === makelogs script @@ -27,5 +27,5 @@ Make sure to execute `node scripts/makelogs` *after* {es} is up and running! [discrete] === CSV upload -You can also use the CSV uploader provided on the {kib} home page. +You can also use the CSV uploader provided on the **Upload file** page available in the list of **Integrations**. Navigate to **Add data** > **Upload file** to upload your data from a file. \ No newline at end of file diff --git a/docs/discover/document-explorer.asciidoc b/docs/discover/document-explorer.asciidoc index 071c9f987502..921e0504f459 100644 --- a/docs/discover/document-explorer.asciidoc +++ b/docs/discover/document-explorer.asciidoc @@ -1,8 +1,7 @@ [[document-explorer]] -== Explore your documents +== Customize the Discover view Fine tune your explorations by customizing *Discover* to bring out the the best view of your documents. -Adjust the chart height, modify the document table, and look inside a document. [role="screenshot"] image::images/hello-field.png[A view of the Discover app] @@ -10,34 +9,27 @@ image::images/hello-field.png[A view of the Discover app] [float] [[document-explorer-c]] -=== Hide or resize the chart +=== Hide or resize areas -Hide or resize the chart for a better fit. +* You can hide and show the chart and the fields list using the available collapse and expand button in the corresponding area. -* To turn off the display of the chart, click -image:images/chart-icon.png[icon button for opening Show/Hide chart menu, width=24px] -to open the *Chart options* menu, and then click *Hide chart*. - -* To change the chart height, drag the resize handle -image:images/resize-icon.png[two-line icon for increasing or decreasing the height of the chart, width=24px] +* Adjust the width and height of each area by dragging their border to the size you want. -The chart size is saved in your browser. - -* To reset the height, open the *Chart options* menu, and then select *Reset to default height*. +The size of each area is saved in your browser for the next time you open **Discover**. [float] [[document-explorer-customize]] === Modify the document table -Customize the appearance of the document table and its contents by resizing the columns and rows, -sorting and modifying the fields, and filtering the documents. +Customize the appearance of the document table and its contents to your liking. + +image:images/discover-customize-table.png[Options to customize the table in Discover] [float] [[document-explorer-columns]] ==== Reorder and resize the columns -* To move a single column, click its header. In the dropdown menu, -click *Move left* or *Move right*. +* To move a single column, open the column's contextual options, and select *Move left* or *Move right* in the available options. * To move multiple columns, click *Columns*. In the pop-up, drag the column names to their new order. @@ -46,17 +38,31 @@ In the pop-up, drag the column names to their new order. + Column widths are stored with a saved search. When you visualize saved searches on dashboards, the saved search appears the same as in **Discover**. +[float] +[[document-explorer-density]] +==== Customize the table density + +You can adjust the density of the table from the **Display options** located in the table toolbar. This can be particularly useful when scrolling through many results. [float] [[document-explorer-row-height]] ==== Adjust the row height To set the row height to one or more lines, or automatically -adjust the height to fit the contents, click the row height icon -image:images/row-height-icon.png[icon to open the Row height pop-up]. +adjust the height to fit the contents, open the **Display options** in the table toolbar, and adjust it as you need. + +You can define different settings for the header row and body rows. + +[float] +[[document-explorer-sample-size]] +==== Limit the sample size + +When the number of results returned by your search query (displayed at the top of the **Documents** or **Results** tab) is greater than the value of <>, the number of results displayed in the table is limited to the configured value by default. You can adjust the initial sample size for searches to any number between 10 and `discover:sampleSize` from the **Display options** located in the table toolbar. + +On the last page of the table, a message indicates that you've reached the end of the loaded search results. From that message, you can choose to load more results to continue exploring. + +image:images/discover-limit-sample-size.png[Limit sample size in Discover] -[role="screenshot"] -image::images/document-explorer-row-height.png[Row height settings for the document table, width="50%"] [float] [[document-explorer-sort-data]] @@ -70,7 +76,7 @@ column header, and then select the sort order. To sort by multiple fields: -. Click the *field sorted* option. +. Click the *Sort fields* option. + [role="screenshot"] image::images/document-explorer-sort-data.png[Pop-up in document table for sorting columns, width="50%"] @@ -106,62 +112,18 @@ Narrow your results to a subset of documents so you're comparing just the data o . Select the documents you want to compare. -. Click the *documents selected* option, and then select *Show selected documents only*. +. Click the *Selected* option, and then select *Show selected documents only*. + [role="screenshot"] -image::images/document-explorer-compare-data.png[Compare data in the document table, width="50%"] - -[float] -[[document-explorer-configure-table]] -==== Set the number of rows per page - -To change the numbers of rows you want to display on each page, use the *Rows per page* menu. The default is 100 rows per page. - -[role="screenshot"] -image::images/document-table-rows-per-page.png["Menu with options for setting the number of rows in the document table"] +image::images/document-explorer-compare-data.png[Compare data in the document table, width="40%"] +You can also compare individual field values using the <>. [float] -[[document-explorer-expand-documents]] - -=== Go inside a document - -Dive into an individual document to inspect its fields, set filters, and view -the documents that occurred before and after it. - -. Click the expand icon -image:images/expand-icon-2.png[double arrow icon to open a flyout with the document details]. -+ -You can view the document in two ways. The **Table** view displays the document fields row-by-row. -The **JSON** (JavaScript Object Notation) view allows you to look at how {es} returns the document. -+ -[role="screenshot"] -image::images/document-table-expanded.png[Expanded view of the document table] -+ -. In the *Table* view, scan through the fields and their values, or search for a field by name. - -. When you find a field of interest, -hover your mouse over the *Actions* column -to: -.. Filter the results to include or exclude specific fields or values. -.. Toggle the field in or out the document table. -.. Pin the field so it stays at the top. - -. To navigate to the next and previous documents, click the < and > arrows at the top of the view. +[[document-explorer-configure-table]] +==== Set the number of results per page -. To create a view of the document that you can bookmark and share, click **Single document**. -+ -[role="screenshot"] -image::images/discover-view-single-document.png[Discover single document view] -+ -The link is valid for the time the document is available in Elasticsearch. To create a customized view of the document, -you can create <>. +To change the numbers of results you want to display on each page, use the *Rows per page* menu. The default is 100 results per page. -. To view documents that occurred before or after the event you are looking at, click **Surrounding documents**. -+ -Documents are displayed using the same set of columns as the *Discover* view from which -the context was opened. The filters you applied are also carried over. Pinned -filters remain active, while other filters are copied in a disabled state. -+ [role="screenshot"] -image::images/discover-context.png[Image showing context view feature, with anchor documents highlighted in blue] +image::images/document-table-rows-per-page.png["Menu with options for setting the number of results in the document table"] diff --git a/docs/discover/field-statistics.asciidoc b/docs/discover/field-statistics.asciidoc index 8dccc0d4a5bb..dc83d226ff36 100644 --- a/docs/discover/field-statistics.asciidoc +++ b/docs/discover/field-statistics.asciidoc @@ -12,7 +12,7 @@ for the data and its cardinality? This example explores the fields in the <>, or you can use your own data. -. Open the main menu, and click *Discover*. +. Go to *Discover*. . Expand the {data-source} dropdown, and select *Kibana Sample Data Logs*. diff --git a/docs/discover/get-started-discover.asciidoc b/docs/discover/get-started-discover.asciidoc new file mode 100644 index 000000000000..ec44f977f4aa --- /dev/null +++ b/docs/discover/get-started-discover.asciidoc @@ -0,0 +1,356 @@ +[[discover-get-started]] +== Explore fields and data with Discover + +Learn how to use *Discover* to: + +- **Select** and **filter** your {es} data. +- **Explore** the fields and content of your data in depth. +- **Present** your findings in a visualization. + +*Prerequisites:* + +- If you don’t already have {kib}, https://www.elastic.co/cloud/elasticsearch-service/signup?baymax=docs-body&elektra=docs[start a free trial] on Elastic Cloud. +- You must have data in {es}. Examples on this page use the +<>, but you can use your own data. +- You should have an understanding of {ref}/documents-indices.html[{es} documents and indices] +and <>. + + +[float] +[[find-the-data-you-want-to-use]] +=== Load data into Discover + +Select the data you want to explore, and then specify the time range in which to view that data. + +. Find **Discover** in the navigation menu or by using the <>. + +. Select the data view that contains the data you want to explore. ++ +TIP: {kib} requires a <> to access your Elasticsearch data. A {data-source} can point to one or more indices, {ref}/data-streams.html[data streams], or {ref}/alias.html[index aliases]. When adding data to {es} using one of the many integrations available, sometimes data views are created automatically, but you can also create your own. ++ +If you're using sample data, data views are automatically created and are ready to use. ++ +[role="screenshot"] +image::images/discover-data-view.png[How to set the {data-source} in Discover, width="40%"] + +. If needed, adjust the <>, for example by setting it to the *Last 7 days*. ++ +The range selection is based on the default time field in your data view. +If you are using the sample data, this value was set when the data view was created. +If you are using your own data view, and it does not have a time field, the range selection is not available. + +**Discover** is populated with your data and you can view various areas with different information: + +* All fields detected are listed in a dedicated panel. +* A chart allows you to visualize your data. +* A table displays the results of your search. +By default, the table includes a column for the time field and a *Summary* column with an overview of each result. +You can modify the document table to display your fields of interest. + +You can later filter the data that shows in the chart and in the table by specifying a query and changing the time range. + +[float] +[[explore-fields-in-your-data]] +=== Explore the fields in your data + +**Discover** provides utilities designed to help you make sense of your data: + +. In the sidebar, check the available fields. It's very common to have hundreds of fields. Use the search at the top of that sidebar to look for specific terms in the field names. ++ +In this example, we've entered `ma` in the search field to find the `manufacturer` field. ++ +[role="screenshot"] +image:images/discover-sidebar-available-fields.png[Fields list that displays the top five search results, width=40%] ++ +TIP: You can combine multiple keywords or characters. For example, `geo dest` finds `geo.dest` and `geo.src.dest`. + +. Select a field to view its most frequent values. ++ +**Discover** shows the top 10 values and the number of records used to calculate those values. + +. Select the *Plus* icon to add fields to the results table. +You can also drag them from the list into the table. ++ +[role="screenshot"] +image::images/discover-add-icon.png[How to add a field as a column in the table, width="50%"] ++ +When you add fields to the table, the **Summary** column is replaced. ++ +[role="screenshot"] +image:images/document-table.png[Document table with fields for manufacturer, customer_first_name, and customer_last_name] + +. Arrange the view to your liking to display the fields and data you care most about using the various display options of **Discover**. For example, you can change the order and size of columns, expand the table to be in full screen or collapse the chart and the list of fields. Check <>. + +. **Save** your changes to be able to open the same view later on and explore your data further. + + +[float] +[[add-field-in-discover]] +==== Add a field to your {data-source} + +What happens if you forgot to define an important value as a separate field? Or, what if you +want to combine two fields and treat them as one? This is where {ref}/runtime.html[runtime fields] come into play. +You can add a runtime field to your {data-source} from inside of **Discover**, +and then use that field for analysis and visualizations, +the same way you do with other fields. + +. In the sidebar, select *Add a field*. + +. Select the **Type** of the new field. + +. **Name** the field. Name it in a way that corresponds to the way other fields of the data view are named. +You can set a custom label and description for the field to make it more recognizable in your data view. + +. Define the value that you want the field to show. By default, the field value is retrieved from the source data if it already contains a field with the same name. You can customize this with the following options: + +** **Set value**: Define a script that will determine the value to show for the field. For more information on adding fields and Painless scripting language examples, +refer to <>. +** **Set format**: Set your preferred format for displaying the value. Changing the format can affect the value and prevent highlighting in Discover. + +. In the advanced settings, you can adjust the field popularity to make it appear higher or lower in the fields list. By default, Discover orders popular fields from most selected to least selected. + +. **Save** your new field. + +You can now find it in the list of fields and add it to the table. + +In the following example, we're adding 2 fields: A simple "Hello world" field, and a second field that combines and transforms the `customer_first_name` and `customer_last_name` fields of the sample data into a single "customer" field: + +**Hello world field example**: + +* **Name**: `hello` +* **Type**: `Keyword` +* **Set value**: enabled +* **Script**: ++ +```ts +emit("Hello World!"); +``` + +**Customer field example**: + +* **Name**: `customer` +* **Type**: `Keyword` +* **Set value**: enabled +* **Script**: ++ +```ts +String str = doc['customer_first_name.keyword'].value; +char ch1 = str.charAt(0); +emit(doc['customer_last_name.keyword'].value + ", " + ch1); +``` + +[float] +==== Visualize aggregated fields +If a field can be {ref}/search-aggregations.html[aggregated], you can quickly +visualize it in detail by opening it in **Lens** from **Discover**. **Lens** is the default visualization editor in {kib}. + +. In the list of fields, find an aggregatable field. For example, with the sample data, you can look for `day_of_week`. ++ +[role="screenshot"] +image:images/discover-day-of-week.png[Top values for the day_of_week field, plus Visualize button, width=50%] + +. In the popup, click **Visualize**. ++ +{kib} creates a **Lens** visualization best suited for this field. + +. In **Lens**, from the *Available fields* list, drag and drop more fields to refine the visualization. In this example, we're adding the `manufacturer.keyword` field onto the workspace, which automatically adds a breakdown of the top values to the visualization. ++ +[role="screenshot"] +image:images/discover-from-visualize.png[Visualization that opens from Discover based on your data] + +. Save the visualization if you'd like to add it to a dashboard or keep it in the Visualize library for later use. + +For geo point fields (image:images/geoip-icon.png[Geo point field icon, width=20px]), +if you click **Visualize**, +your data appears in a map. + +[role="screenshot"] +image:images/discover-maps.png[Map containing documents] + + +[float] +[[compare-documents-in-discover]] +==== Compare documents + +You can use *Discover* to compare and diff the field values of multiple results or documents in the table. + +. Select the results you want to compare from the Documents or Results tab in Discover. + +. From the **Selected** menu in the table toolbar, choose **Compare selected**. The comparison view opens and shows the selected results next to each other. + +. Compare the values of each field. By default the first result selected shows as the reference for displaying differences in the other results. When the value remains the same for a given field, it's displayed in green. When the value differs, it's displayed in red. ++ +TIP: You can change the result used as reference by selecting **Pin for comparison** in the contextual menu of any other result. ++ +image:images/discover-compare-rows.png[Comparison view in Discover] + +. Optionally, customize the **Comparison settings** to your liking. You can for example choose to not highlight the differences, to show them more granularly at the line, word, or character level, or even to hide fields where the value matches for all results. + +. Exit the comparison view at any time using the **Exit comparison mode** button. + +[float] +[[copy-row-content]] +==== Copy results as text or JSON + +You can quickly copy the content currently displayed in the table for one or several results to your clipboard. + +. Select the results you want to copy. + +. Open the **Selected** menu in the table toolbar, and select **Copy selection as text** or **Copy documents as JSON**. + +The content is copied to your clipboard in the selected format. +Fields that are not currently added to the table are ignored. + +[float] +[[look-inside-a-document]] +==== Explore individual result or document details in depth + +[[document-explorer-expand-documents]] +Dive into an individual document to view its fields and the documents +that occurred before and after it. + +. In the document table, click the expand icon +image:images/expand-icon-2.png[double arrow icon to open a flyout with the document details] +to show document details. ++ +[role="screenshot"] +image:images/document-table-expanded.png[Table view with document expanded] + +. Scan through the fields and their values. You can filter the table in several ways: +** If you find a field of interest, +hover your mouse over the *Field* or *Value* columns for filters and additional options. +** Use the search above the table to filter for specific fields or values, or filter by field type using the options to the right of the search field. +** You can pin some fields by clicking the left column to keep them displayed even if you filter the table. ++ +TIP: You can restrict the fields listed in the detailed view to just the fields that you explicitly added to the **Discover** table, using the **Selected only** toggle. In ES|QL mode, you also have an option to hide fields with null values. + +. To navigate to a view of the document that you can bookmark and share, select ** View single document**. + +. To view documents that occurred before or after the event you are looking at, select +**View surrounding documents**. + + + + +[float] +[[search-in-discover]] +=== Search and filter data + +[float] +==== Default mode: Search and filter using KQL + +One of the unique capabilities of **Discover** is the ability to combine +free text search with filtering based on structured data. +To search all fields, enter a simple string in the query bar. + +[role="screenshot"] +image:images/discover-search-field.png[Search field in Discover] + +To search particular fields and +build more complex queries, use the <>. +As you type, KQL prompts you with the fields you can search and the operators +you can use to build a structured query. + +For example, search the ecommerce sample data for documents where the country matches US: + +. Enter `g`, and then select *geoip.country_iso_code*. +. Select *:* for equals, and *US* for the value, and then click the refresh button or press the Enter key. +. For a more complex search, try: ++ +```ts +geoip.country_iso_code : US and products.taxless_price >= 75 +``` + +[[filter-in-discover]] +With the query input, you can filter data using the KQL or Lucene languages. You can also use the **Add filter** function available next to the query input to build your filters one by one or define them as Query DSL. + +For example, exclude results from the ecommerce sample data view where day of week is not Wednesday: + +. Click image:images/add-icon.png[Add icon] next to the query bar. +. In the *Add filter* pop-up, set the field to *day_of_week*, the operator to *is not*, +and the value to *Wednesday*. ++ +[role="screenshot"] +image:images/discover-add-filter.png[Add filter dialog in Discover] + +. Click **Add filter**. +. Continue your exploration by adding more filters. +. To remove a filter, click the close icon (x) next to its name in the filter bar. + +[float] +==== Search and filter using ES|QL + +You can use **Discover** with the Elasticsearch Query Language, ES|QL. When using ES|QL, +you don't have to select a data view. It's your query that determines the data to explore and display in Discover. + +You can switch to the ES|QL mode of Discover from the application menu bar. + +Note that in ES|QL mode, the **Documents** tab is named **Results**. + +Learn more about how to use ES|QL queries in <>. + + + +[float] +[[save-discover-search]] +==== Save your search for later use + +Save your search so you can use it later, generate a CSV report, or use it to create visualizations, dashboards, and Canvas workpads. +Saving a search saves the query text, filters, +and current view of *Discover*, including the columns selected in +the document table, the sort order, and the {data-source}. + +. In the application menu bar, click **Save**. + +. Give your search a title and a description. + +. Optionally store <> and the time range with the search. + +. Click **Save**. + +[float] +[[share-your-findings]] +==== Share your search + +To share your search and **Discover** view with a larger audience, click *Share* in the application menu bar. +For detailed information about the sharing options, refer to <>. + + +[float] +[[alert-from-Discover]] +=== Generate alerts + +From *Discover*, you can create a rule to periodically +check when data goes above or below a certain threshold within a given time interval. + +. Ensure that your data view, +query, and filters fetch the data for which you want an alert. +. In the application menu bar, click *Alerts > Create search threshold rule*. ++ +The *Create rule* form is pre-filled with the latest query sent to {es}. +. <> and <>. + +. Click *Save*. + +For more about this and other rules provided in {alert-features}, go to <>. + + +[float] +=== What’s next? + +* <>. + +* <> to better meet your needs. + +[float] +=== Troubleshooting + +This section references common questions and issues encountered when using Discover. +Also check the following blog post: {blog-ref}troubleshooting-guide-common-issues-kibana-discover-load[Learn how to resolve common issues with Discover.] + +**Some fields show as empty while they should not be, why is that?** + +This can happen in several cases: + +* With runtime fields and regular keyword fields, when the string exceeds the value set for the {ref}/ignore-above.html[ignore_above] setting used when indexing the data into {es}. +* Due to the structure of nested fields, a leaf field added to the table as a column will not contain values in any of its cells. Instead, add the root field as a column to view a JSON representation of its values. Learn more in https://www.elastic.co/de/blog/discover-uses-fields-api-in-7-12[this blog post]. \ No newline at end of file diff --git a/docs/discover/images/discover-add-filter.png b/docs/discover/images/discover-add-filter.png index 3ce158fc4fb8..f72d4074b4b8 100644 Binary files a/docs/discover/images/discover-add-filter.png and b/docs/discover/images/discover-add-filter.png differ diff --git a/docs/discover/images/discover-compare-rows.png b/docs/discover/images/discover-compare-rows.png new file mode 100644 index 000000000000..868a17fd7ca2 Binary files /dev/null and b/docs/discover/images/discover-compare-rows.png differ diff --git a/docs/discover/images/discover-customize-table.png b/docs/discover/images/discover-customize-table.png new file mode 100644 index 000000000000..a0aba47f6cd1 Binary files /dev/null and b/docs/discover/images/discover-customize-table.png differ diff --git a/docs/discover/images/discover-data-view.png b/docs/discover/images/discover-data-view.png index 869fc9b92881..e6c3a9aa832d 100644 Binary files a/docs/discover/images/discover-data-view.png and b/docs/discover/images/discover-data-view.png differ diff --git a/docs/discover/images/discover-limit-sample-size.png b/docs/discover/images/discover-limit-sample-size.png new file mode 100644 index 000000000000..1e8628ebace5 Binary files /dev/null and b/docs/discover/images/discover-limit-sample-size.png differ diff --git a/docs/discover/images/document-explorer-compare-data.png b/docs/discover/images/document-explorer-compare-data.png index 36560dcabd13..2a980f897739 100644 Binary files a/docs/discover/images/document-explorer-compare-data.png and b/docs/discover/images/document-explorer-compare-data.png differ diff --git a/docs/discover/images/document-table-expanded.png b/docs/discover/images/document-table-expanded.png index a6fee908b668..f73c7d08fe09 100644 Binary files a/docs/discover/images/document-table-expanded.png and b/docs/discover/images/document-table-expanded.png differ diff --git a/docs/discover/images/document-table.png b/docs/discover/images/document-table.png index 8fbabe4703b2..ab9141cbb9b5 100644 Binary files a/docs/discover/images/document-table.png and b/docs/discover/images/document-table.png differ diff --git a/docs/discover/images/esql-custom-time-series.png b/docs/discover/images/esql-custom-time-series.png new file mode 100644 index 000000000000..1be4e5f137fc Binary files /dev/null and b/docs/discover/images/esql-custom-time-series.png differ diff --git a/docs/discover/images/esql-full-query.png b/docs/discover/images/esql-full-query.png index e4f5faeef3cf..6bcfba71c4cd 100644 Binary files a/docs/discover/images/esql-full-query.png and b/docs/discover/images/esql-full-query.png differ diff --git a/docs/discover/images/esql-limit.png b/docs/discover/images/esql-limit.png index b03ecdcc091e..37a59e0c6c79 100644 Binary files a/docs/discover/images/esql-limit.png and b/docs/discover/images/esql-limit.png differ diff --git a/docs/discover/images/esql-machine-os-ram.png b/docs/discover/images/esql-machine-os-ram.png index ad46d88b219f..8e2e548a7b31 100644 Binary files a/docs/discover/images/esql-machine-os-ram.png and b/docs/discover/images/esql-machine-os-ram.png differ diff --git a/docs/discover/images/esql-no-time-series.png b/docs/discover/images/esql-no-time-series.png new file mode 100644 index 000000000000..779269582e7b Binary files /dev/null and b/docs/discover/images/esql-no-time-series.png differ diff --git a/docs/discover/images/hello-field.png b/docs/discover/images/hello-field.png index 261cb00acfa4..8aee22bf2a84 100644 Binary files a/docs/discover/images/hello-field.png and b/docs/discover/images/hello-field.png differ diff --git a/docs/discover/log-pattern-analysis.asciidoc b/docs/discover/log-pattern-analysis.asciidoc index b4bd9fec29ec..5131b68a073b 100644 --- a/docs/discover/log-pattern-analysis.asciidoc +++ b/docs/discover/log-pattern-analysis.asciidoc @@ -7,7 +7,7 @@ Log pattern analysis works on every text field. This example uses the <>, or you can use your own data. -. Open the main menu, and click *Discover*. +. Go to *Discover*. . Expand the {data-source} dropdown, and select *Kibana Sample Data Logs*. diff --git a/docs/discover/save-search.asciidoc b/docs/discover/save-search.asciidoc index 10abef2e4a1b..024fd97ab107 100644 --- a/docs/discover/save-search.asciidoc +++ b/docs/discover/save-search.asciidoc @@ -43,7 +43,7 @@ used for the saved search is also automatically selected. [float] === Add search results to a dashboard -. Open the main menu, and then click *Dashboard*. +. Go to *Dashboards*. . Open or create the dashboard, then click *Edit*. . Click *Add from library*. . From the *Types* dropdown, select *Saved search*. diff --git a/docs/discover/search-sessions.asciidoc b/docs/discover/search-sessions.asciidoc index e7d7466b5ae0..fe1e945e676f 100644 --- a/docs/discover/search-sessions.asciidoc +++ b/docs/discover/search-sessions.asciidoc @@ -52,8 +52,8 @@ image::images/search-session-awhile.png[Search Session indicator displaying the Once you save a search session, you can start a new search, navigate to a different application, or close the browser. -. To view your saved searches, open the main menu, and then click -*Stack Management > Search Sessions*. +. To view your saved searches, go to the +*Search Sessions* management page using the navigation menu or the <>. For a saved or completed session, you can also open this view from the search sessions popup. + diff --git a/docs/discover/search.asciidoc b/docs/discover/search.asciidoc index 4f4f8f5b48d1..439c5c443cc0 100644 --- a/docs/discover/search.asciidoc +++ b/docs/discover/search.asciidoc @@ -113,8 +113,7 @@ To save the current search: . Click *Save* in the toolbar. . Enter a name for the search and click *Save*. -To import, export, and delete saved searches, open the main menu, -then click *Stack Management > Saved Objects*. +To import, export, and delete saved searches, go to the *Saved Objects* management page using the navigation menu or the <>. ==== Open a saved search To load a saved search into Discover: diff --git a/docs/discover/try-esql.asciidoc b/docs/discover/try-esql.asciidoc index 53862be75f01..149ce80dbb34 100644 --- a/docs/discover/try-esql.asciidoc +++ b/docs/discover/try-esql.asciidoc @@ -5,11 +5,17 @@ The Elasticsearch Query Language, {esql}, makes it easier to explore your data w In this tutorial we'll use the {kib} sample web logs in Discover and Lens to explore the data and create visualizations. +[TIP] +==== +For the complete {esql} documentation, including tutorials, examples and the full syntax reference, refer to the {ref}/esql.html[{es} documentation]. +For a more detailed overview of {esql} in {kib}, refer to {ref}/esql-kibana.html[Use {esql} in Kibana]. +==== + [float] [[prerequisite]] === Prerequisite -To be able to select **Language {esql}** from the Data views menu the `enableESQL` setting must be enabled from **Stack Management > Advanced Settings**. It is enabled by default. +To view the {esql} option in **Discover**, the `enableESQL` setting must be enabled from Kibana's **Advanced Settings**. It is enabled by default. [float] [[tutorial-try-esql]] @@ -17,24 +23,24 @@ To be able to select **Language {esql}** from the Data views menu the `enableESQ To load the sample data: -. On the home page, click **Try sample data**. -. Click **Other sample data sets**. -. On the Sample web logs card, click **Add data**. -. Open the main menu and select *Discover*. -. From the Data views menu, select *Language {esql}*. +. <>. +. Go to *Discover*. +. Select *Try {esql}* from the application menu bar. Let's say we want to find out what operating system users have and how much RAM is on their machine. . Set the time range to **Last 7 days**. -. Expand image:images/expand-icon-2.png[An image of the expand icon] the query bar. -. Put each processing command on a new line for better readability. . Copy the query below: + [source,esql] ---- -FROM kibana_sample_data_logs -| KEEP machine.os, machine.ram +FROM kibana_sample_data_logs <1> +| KEEP machine.os, machine.ram <2> ---- +<1> We're specifically looking for data from the sample web logs we just installed. +<2> We're only keeping the `machine.os` and `machine.ram` fields in the results table. ++ +TIP: Put each processing command on a new line for better readability. + . Click **▶Run**. + @@ -57,12 +63,14 @@ FROM kibana_sample_data_logs | LIMIT 10 ---- + -. Click **▶Run**. +. Click **▶Run** again. You can notice that the table is now limited to 10 results. The visualization also updated automatically based on the query, and broke down the data for you. ++ +NOTE: When you don't specify any specific fields to retain using `KEEP`, the visualization isn't broken down automatically. Instead, an additional option appears above the visualization and lets you select a field manually. + [role="screenshot"] image:images/esql-limit.png[An image of the extended query result] -Let's sort the data by machine ram and filter out the destination GB. +We will now take it a step further to sort the data by machine ram and filter out the `GB` destination. . Copy the query below: + @@ -75,18 +83,51 @@ FROM kibana_sample_data_logs | LIMIT 10 ---- + -. Click **▶Run**. +. Click **▶Run** again. The table and visualization no longer show results for which the `geo.dest` field value is "GB", and the results are now sorted in descending order in the table based on the `machine.ram` field. + [role="screenshot"] image:images/esql-full-query.png[An image of the full query result] + . Click **Save** to save the query and visualization to a dashboard. -To make changes to the visualization you can use the visualization drop-down. To make changes to the colors used or the axes, or click the pencil icon. This opens an in-line editor where you can change the colors and axes of the visualization. +[float] +==== Edit the ES|QL visualization + +You can make changes to the visualization by clicking the pencil icon. This opens additional settings that let you adjust the chart type, axes, breakdown, colors, and information displayed to your liking. If you're not sure which route to go, check one of the suggestions available in the visualization editor. + +If you'd like to keep the visualization and add it to a dashboard, you can save it using the floppy disk icon. + +[float] +==== ES|QL and time series data + +By default, ES|QL identifies time series data when an index contains a `@timestamp` field. This enables the time range selector and visualization options for your query. + +If your index doesn't have an explicit `@timestamp` field, but has a different time field, you can still enable the time range selector and visualization options by calling the `?_start` and `?_tend` parameters in your query. + +For example, the eCommerce sample data set doesn't have a `@timestamp` field, but has an `order_date` field. + +By default, when querying this data set, time series capabilities aren't active. No visualization is generated and the time picker is disabled. + +[source,esql] +---- +FROM kibana_sample_data_ecommerce +| KEEP customer_first_name, email, products._id.keyword +---- + +image::images/esql-no-time-series.png[ESQL query without time series capabilities enabled] + +While still querying the same data set, by adding the `?_start` and `?_tend` parameters based on the `order_date` field, **Discover** enables times series capabilities. + +[source,esql] +---- +FROM kibana_sample_data_ecommerce +| WHERE order_date >= ?_tstart and order_date <= ?_tend +---- + +image::images/esql-custom-time-series.png[ESQL query with a custom time field enabled] + + + + -[TIP] -==== -For the complete {esql} documentation, including tutorials, examples and the full syntax reference, refer to the {ref}/esql.html[{es} documentation]. -For a more detailed overview of {esql} in {kib}, refer to {ref}/esql-kibana.html[Use {esql} in Kibana]. -==== diff --git a/docs/fleet/fleet.asciidoc b/docs/fleet/fleet.asciidoc index dfee4c36171d..52c282555700 100644 --- a/docs/fleet/fleet.asciidoc +++ b/docs/fleet/fleet.asciidoc @@ -31,7 +31,7 @@ You can make a complete clone of a whole managed dashboard. If you clone a panel To clone a dashboard: -. Open the main menu (≡) and click *Dashboards*. +. Go to *Dashboards*. . Click on the name of the managed dashboard to view the dashboard. . Click *Clone* in the toolbar. . Click *Save and return* after editing the dashboard. diff --git a/docs/getting-started/quick-start-guide.asciidoc b/docs/getting-started/quick-start-guide.asciidoc index 1a25f2f1ec9f..6be9dbfa2edb 100644 --- a/docs/getting-started/quick-start-guide.asciidoc +++ b/docs/getting-started/quick-start-guide.asciidoc @@ -22,18 +22,19 @@ include::{docs-root}/shared/cloud/ess-getting-started.asciidoc[] [float] [[gs-get-data-into-kibana]] -== Add the sample data +== Add sample data Sample data sets come with sample visualizations, dashboards, and more to help you explore {kib} before you ingest or add your own data. -. On the home page, click *Try sample data*. +. Open the **Integrations** page from the navigation menu or using the <>. -. Click *Other sample data sets*. +. In the list of integrations, select **Sample Data**. -. On the *Sample eCommerce orders* card, click *Add data*. -+ -[role="screenshot"] -image::images/addData_sampleDataCards_8.6.0.png[Add data UI for the sample data sets] +. On the page that opens, select *Other sample data sets*. + +. Install the sample data sets that you want. + +Once installed, you can access the sample data in the various {kib} apps available to you. [float] [[explore-the-data]] @@ -41,7 +42,7 @@ image::images/addData_sampleDataCards_8.6.0.png[Add data UI for the sample data *Discover* displays the data in an interactive histogram that shows the distribution of data, or documents, over time, and a table that lists the fields for each document that matches the {data-source}. To view a subset of the documents, you can apply filters to the data, and customize the table to display only the fields you want to explore. -. Open the main menu, then click *Discover*. +. Go to *Discover*. . Change the <> to *Last 7 days*. + @@ -67,7 +68,7 @@ image::images/availableFields_discover_8.4.0.png[Discover table that displays on A dashboard is a collection of panels that you can use to visualize the data. Panels contain visualizations, interactive controls, text, and more. -. Open the main menu, then click *Dashboard*. +. Go to *Dashboards*. . Click *[eCommerce] Revenue Dashboard*. + diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index d6ae2aecaf27..f6b8e6844ce0 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -20,7 +20,7 @@ indicator is displayed: [role="screenshot"] image::images/settings-read-only-badge.png[Example of Advanced Settings Management's read only access indicator in Kibana's header] -To add the privilege, open the main menu, then click *Stack Management > Roles*. +To add the privilege, go to the *Roles* management page using the navigation menu or the <>. For more information on granting access to {kib}, refer to <>. @@ -30,7 +30,7 @@ For more information on granting access to {kib}, refer to < Advanced Settings*. +. Go to the *Advanced settings* page using the navigation menu or the <>. . Click *Space Settings*. . Scroll or search for the setting. . Make your change, then click *Save changes*. @@ -644,7 +644,7 @@ Disable this option if you prefer to use the new heatmap charts with improved pe Change the settings that apply only to {kib} spaces. -. Open the main menu, then click *Stack Management > Advanced Settings*. +. Go to the *Advanced settings* page using the navigation menu or the <>. . Click *Global Settings*. . Scroll or search for the setting. . Make your change, then click *Save changes*. diff --git a/docs/management/connectors/action-types/jira.asciidoc b/docs/management/connectors/action-types/jira.asciidoc index 906a2945d82d..2111de7a77ce 100644 --- a/docs/management/connectors/action-types/jira.asciidoc +++ b/docs/management/connectors/action-types/jira.asciidoc @@ -14,7 +14,7 @@ The Jira connector uses the https://developer.atlassian.com/cloud/jira/platform/ [[jira-compatibility]] === Compatibility -Jira on-premise deployments (Server and Data Center) are not supported. +Jira Cloud and Jira Data Center are supported. Jira on-premise deployments are not supported. [float] [[define-jira-ui]] @@ -37,7 +37,7 @@ Name:: The name of the connector. URL:: Jira instance URL. Project key:: Jira project key. Email:: The account email for HTTP Basic authentication. -API token:: Jira API authentication token for HTTP Basic authentication. +API token:: Jira API authentication token for HTTP Basic authentication. For Jira Data Center, this value should be the password associated with the email owner. [float] [[jira-action-configuration]] diff --git a/docs/management/connectors/action-types/servicenow-sir.asciidoc b/docs/management/connectors/action-types/servicenow-sir.asciidoc index 4c3b6d15bf59..295a326b490b 100644 --- a/docs/management/connectors/action-types/servicenow-sir.asciidoc +++ b/docs/management/connectors/action-types/servicenow-sir.asciidoc @@ -285,7 +285,8 @@ IMPORTANT: Deprecated connectors will continue to function with the rules they w To update a deprecated connector: -. Open the main menu and go to *{stack-manage-app} > {connectors-ui}*. +. Go to the *{connectors-ui}* page using the navigation menu or the +<>. . Select the deprecated connector to open the *Edit connector* flyout. . In the warning message, click *Update this connector*. . Complete the guided steps in the *Edit connector* flyout. diff --git a/docs/management/connectors/action-types/servicenow.asciidoc b/docs/management/connectors/action-types/servicenow.asciidoc index 83f8bd050d04..852db21e7754 100644 --- a/docs/management/connectors/action-types/servicenow.asciidoc +++ b/docs/management/connectors/action-types/servicenow.asciidoc @@ -338,7 +338,8 @@ IMPORTANT: Deprecated connectors will continue to function with the rules they w To update a deprecated connector: -. Open the main menu and go to *{stack-manage-app} > {connectors-ui}*. +. Go to the *{connectors-ui}* page using the navigation menu or the +<>. . Select the deprecated connector to open the *Edit connector* flyout. . In the warning message, click *Update this connector*. . Complete the guided steps in the *Edit connector* flyout. diff --git a/docs/management/connectors/pre-configured-connectors.asciidoc b/docs/management/connectors/pre-configured-connectors.asciidoc index 8f9536331bb1..06a77a12beab 100644 --- a/docs/management/connectors/pre-configured-connectors.asciidoc +++ b/docs/management/connectors/pre-configured-connectors.asciidoc @@ -66,7 +66,8 @@ Sensitive properties, such as passwords, can also be stored in the [[managing-preconfigured-connectors]] === View preconfigured connectors -When you open the main menu, click *{stack-manage-app} > {connectors-ui}*. +go to the *{connectors-ui}* page using the navigation menu or the +<>. Preconfigured connectors appear regardless of which space you are in. They are tagged as “preconfigured”, and you cannot delete them. diff --git a/docs/management/manage-data-views.asciidoc b/docs/management/manage-data-views.asciidoc index 936d764433fe..4c6a0d77b7a9 100644 --- a/docs/management/manage-data-views.asciidoc +++ b/docs/management/manage-data-views.asciidoc @@ -39,7 +39,7 @@ then define the field values by emitting a single value using the {ref}/modules-scripting-painless.html[Painless scripting language]. You can also add runtime fields in <> and <>. -. Open the main menu, then click *Stack Management > Data Views*. +. Go to the *Data Views* management page using the navigation menu or the <>. . Select the data view that you want to add the runtime field to, then click *Add field*. @@ -162,7 +162,7 @@ else { Edit the settings for runtime fields, or remove runtime fields from data views. -. Open the main menu, then click *Stack Management > Data Views*. +. Go to the *Data Views* management page using the navigation menu or the <>. . Select the data view that contains the runtime field you want to manage, then open the runtime field edit options or delete the runtime field. @@ -198,7 +198,7 @@ https://www.elastic.co/blog/using-painless-kibana-scripted-fields[Using Painless Create and add scripted fields to your data views. -. Open the main menu, then click *Stack Management > Data Views*. +. Go to the *Data Views* management page using the navigation menu or the <>. . Select the data view you want to add a scripted field to. @@ -214,7 +214,7 @@ For more information about scripted fields in {es}, refer to {ref}/modules-scrip [[update-scripted-field]] ==== Manage scripted fields -. Open the main menu, then click *Stack Management > Data Views*. +. Go to the *Data Views* management page using the navigation menu or the <>. . Select the data view that contains the scripted field you want to manage. @@ -230,7 +230,7 @@ exceptions when you view the dynamically generated data. {kib} uses the same field types as {es}, however, some {es} field types are unsupported in {kib}. To customize how {kib} displays data fields, use the formatting options. -. Open the main menu, then click *Stack Management > Data Views*. +. Go to the *Data Views* management page using the navigation menu or the <>. . Click the data view that contains the field you want to change. diff --git a/docs/management/managing-licenses.asciidoc b/docs/management/managing-licenses.asciidoc index 837a83f0aae3..14b359276356 100644 --- a/docs/management/managing-licenses.asciidoc +++ b/docs/management/managing-licenses.asciidoc @@ -11,14 +11,16 @@ If you need more than 30 days to complete your evaluation, request an extended trial at {extendtrial}. To view the status of your license, start a trial, or install a new -license, open the main menu, then click *Stack Management > License Management*. +license, go to the *License Management* page using the navigation menu or the +<>. [discrete] === Required permissions The `manage` cluster privilege is required to access *License Management*. -To add the privilege, open the main menu, then click *Stack Management > Roles*. +To add the privilege, go to the *Roles* management page using the navigation menu or the +<>. [discrete] [[license-expiration]] diff --git a/docs/management/managing-saved-objects.asciidoc b/docs/management/managing-saved-objects.asciidoc index 231843081e7e..1e2e5d194cd3 100644 --- a/docs/management/managing-saved-objects.asciidoc +++ b/docs/management/managing-saved-objects.asciidoc @@ -4,7 +4,8 @@ Edit, import, export, and copy your saved objects. These objects include dashboards, visualizations, maps, {data-sources}, *Canvas* workpads, and other saved objects. -To get started, open the main menu, and then click *Stack Management > Saved Objects*. +You can find the *Saved Objects* page using the navigation menu or the +<>. [role="screenshot"] image::images/management-saved-objects.png[Saved Objects] @@ -14,7 +15,8 @@ image::images/management-saved-objects.png[Saved Objects] To access *Saved Objects*, you must have the required `Saved Objects Management` {kib} privilege. -To add the privilege, open the main menu, and then click *Stack Management > Roles*. +To add the privilege, go to the *Roles* management page using the navigation menu or the +<>. NOTE: Granting access to `Saved Objects Management` authorizes users to manage all saved objects in {kib}, including objects that are managed by diff --git a/docs/management/managing-tags.asciidoc b/docs/management/managing-tags.asciidoc index b9fbe8576078..20e5fa897c0a 100644 --- a/docs/management/managing-tags.asciidoc +++ b/docs/management/managing-tags.asciidoc @@ -5,7 +5,8 @@ Use tags to categorize your saved objects, then filter for related objects based on shared tags. -To get started, open the main menu, and then click *Stack Management > Tags*. +To get started, go to the *Tags* management page using the navigation menu or the +<>. [role="screenshot"] image::images/tags/tag-management-section.png[Tags management] @@ -15,8 +16,8 @@ image::images/tags/tag-management-section.png[Tags management] To create tags, you must meet the minimum requirements. -* Access to *Tags* requires the `Tag Management` Kibana privilege. To add the privilege, open the main menu, -and then click *Stack Management > Roles*. +* Access to *Tags* requires the `Tag Management` Kibana privilege. To add the privilege, go to the *Roles* page using the navigation menu or the +<>. * The `read` privilege allows you to assign tags to the saved objects for which you have write permission. * The `write` privilege enables you to create, edit, and delete tags. diff --git a/docs/management/rollups/create_and_manage_rollups.asciidoc b/docs/management/rollups/create_and_manage_rollups.asciidoc index 2f9ede62c0b0..c6e379c3d53a 100644 --- a/docs/management/rollups/create_and_manage_rollups.asciidoc +++ b/docs/management/rollups/create_and_manage_rollups.asciidoc @@ -9,7 +9,8 @@ an index pattern, and then rolls it into a new index. Rollup indices are a good way to compactly store months or years of historical data for use in visualizations and reports. -To get started, open the main menu, then click *Stack Management > Rollup Jobs*. +You can go to the *Rollup Jobs* page using the navigation menu or the +<>. [role="screenshot"] image::images/management_rollup_list.png[List of currently active rollup jobs] @@ -23,7 +24,8 @@ detailed information. The `manage_rollup` cluster privilege is required to access *Rollup jobs*. -To add the privilege, open the main menu, then click *Stack Management > Roles*. +To add the privilege, go to the *Roles* management page using the navigation menu or the +<>. [float] [[create-and-manage-rollup-job]] @@ -142,7 +144,8 @@ rollup index, or you can remove or archive it using Your next step is to visualize your rolled up data in a vertical bar chart. Most visualizations support rolled up data, with the exception of Timelion and Vega visualizations. -. Open the main menu, then click *Stack Management > Data Views*. +. Go to the *Data Views* page using the navigation menu or the +<>. . Click *Create data view*, and select *Rollup data view* from the dropdown. @@ -153,7 +156,7 @@ The notation for a combination data view with both raw and rolled up data is `rollup_logstash,kibana_sample_data_logs`. In this data view, `rollup_logstash` matches the rollup index and `kibana_sample_data_logs` matches the raw data. -. Open the main menu, click *Dashboard*, then *Create dashboard*. +. Go to *Dashboards*, then select *Create dashboard*. . Set the <> to *Last 90 days*. diff --git a/docs/management/watcher-ui/index.asciidoc b/docs/management/watcher-ui/index.asciidoc index 2e941cb86ca0..7f85376ad569 100644 --- a/docs/management/watcher-ui/index.asciidoc +++ b/docs/management/watcher-ui/index.asciidoc @@ -8,8 +8,8 @@ Watches are helpful for analyzing mission-critical and business-critical streaming data. For example, you might watch application logs for performance outages or audit access logs for security threats. -To get started, open the main menu, -then click *Stack Management > Watcher*. +Go to the *Watcher* page using the navigation menu or the +<>. With this UI, you can: * <> @@ -39,7 +39,7 @@ and either of these Watcher roles: * `watcher_admin`. You can perform all Watcher actions, including create and edit watches. * `watcher_user`. You can view watches, but not create or edit them. -To manage roles, open the main menu, then click *Stack Management > Roles*, or use the {api-kibana}/group/endpoint-roles[role APIs]. +To manage roles, go to the *Roles* management page, or use the {api-kibana}/group/endpoint-roles[role APIs]. Watches are shared between all users with the same role. NOTE: If you are creating a threshold watch, you must also have the `view_index_metadata` index privilege. See diff --git a/docs/maps/asset-tracking-tutorial.asciidoc b/docs/maps/asset-tracking-tutorial.asciidoc index 32ab099575c9..b1ded453214f 100644 --- a/docs/maps/asset-tracking-tutorial.asciidoc +++ b/docs/maps/asset-tracking-tutorial.asciidoc @@ -35,7 +35,8 @@ To get to the fun of visualizing and alerting on Portland public transport vehic [float] ==== Step 1: Set up an Elasticsearch index -. In Kibana, open the main menu, then click *Dev Tools*. +. In Kibana, go to *Developer tools* using the navigation menu or the +<>. . In *Console*, create the `tri_met_tracks` index lifecyle policy. This policy will keep the events in the hot data phase for 7 days. The data then moves to the warm phase. After 365 days in the warm phase, the data is deleted. + .ILM policy definition @@ -503,7 +504,7 @@ TIP: You may want to tweak this Data View to adjust the field names and number o [float] ==== Step 4: Explore the Portland TriMet data -. Open the main menu, and click *Discover*. +. Go to *Discover*. . Set the data view to *{ems-asset-index-name}*. . Open the <>, and set the time range to the last 15 minutes. . Expand a document and explore some of the fields that you will use later in this tutorial: `trimet.bearing`, `trimet.inCongestion`, `trimet.location`, and `trimet.vehicleID`. @@ -523,7 +524,7 @@ It's hard to get an overview of Portland vehicles by looking at individual event Create your map and set the theme for the default layer to dark mode. -. Open the main menu, and click *Maps*. +. Go to *Maps*. . Click *Create map*. . In the *Layers* list, click *Road map*, and then click *Edit layer settings*. . Open the *Tile service* dropdown, and select *Road map - dark*. diff --git a/docs/maps/geojson-upload.asciidoc b/docs/maps/geojson-upload.asciidoc index f4208663078a..8bd8a32e5d44 100644 --- a/docs/maps/geojson-upload.asciidoc +++ b/docs/maps/geojson-upload.asciidoc @@ -19,8 +19,8 @@ GeoJSON is the most commonly used and flexible option. Follow these instructions to upload a GeoJSON data file, or try the <>. -. Open the main menu, click *Maps*, and then click *Add layer*. -. Click *Uploaded GeoJSON*. +. Go to *Maps*, and select *Add layer*. +. Select *Uploaded GeoJSON*. + [role="screenshot"] image::maps/images/fu_gs_select_source_file_upload.png[] diff --git a/docs/maps/import-geospatial-data.asciidoc b/docs/maps/import-geospatial-data.asciidoc index e84ba3c3cbd2..47d05c5f1d00 100644 --- a/docs/maps/import-geospatial-data.asciidoc +++ b/docs/maps/import-geospatial-data.asciidoc @@ -23,7 +23,7 @@ To upload GeoJSON files, shapefiles, and draw features in {kib} with *Maps*, you * The `create` and `create_index` index privileges for destination indices * To use the index in *Maps*, you must also have the `read` and `view_index_metadata` index privileges for destination indices -To upload delimited files (such as CSV, TSV, or JSON files) on the {kib} home page, you must also have: +To upload delimited files (such as CSV, TSV, or JSON files) from the **Upload file** integration, you must also have: * The `all` {kib} privilege for *Discover* * The `manage_pipeline` or `manage_ingest_pipelines` cluster privilege @@ -33,9 +33,9 @@ To upload delimited files (such as CSV, TSV, or JSON files) on the {kib} home pa [discrete] === Upload delimited files with latitude and longitude columns -On the {kib} home page, you can upload a file and import it into an {es} index with latitude and longitude columns combined into a `geo_point` field. +You can upload a file and import it into an {es} index with latitude and longitude columns combined into a `geo_point` field. -. Go to the {kib} home page and click *Upload a file*. +. Go to the *Integrations* page and select *Upload file*. . Select a file in one of the supported file formats. . Click *Import*. . Select the *Advanced* tab. diff --git a/docs/maps/maps-getting-started.asciidoc b/docs/maps/maps-getting-started.asciidoc index 39579d935275..8dec40df5eb3 100644 --- a/docs/maps/maps-getting-started.asciidoc +++ b/docs/maps/maps-getting-started.asciidoc @@ -31,7 +31,7 @@ refer to <>. [[maps-create]] === Step 1. Create a map -. Open the main menu, and then click *Dashboard*. +. Go to *Dashboards*. . Click **Create dashboard**. . Set the time range to *Last 7 days*. . Click the **Create new Maps** icon image:maps/images/app_gis_icon.png[]. diff --git a/docs/maps/reverse-geocoding-tutorial.asciidoc b/docs/maps/reverse-geocoding-tutorial.asciidoc index 48151281fb07..ec221dfc5fb9 100644 --- a/docs/maps/reverse-geocoding-tutorial.asciidoc +++ b/docs/maps/reverse-geocoding-tutorial.asciidoc @@ -26,12 +26,7 @@ GeoIP is a common way of transforming an IP address to a longitude and latitude. You’ll use the <> that comes with Kibana for this tutorial. Web logs sample data set has longitude and latitude. If your web log data does not contain longitude and latitude, use {ref}/geoip-processor.html[GeoIP processor] to transform an IP address into a {ref}/geo-point.html[geo_point] field. -To install web logs sample data set: - -. On the home page, click *Try sample data*. -. Expand *Other sample data sets*. -. On the *Sample web logs* card, click *Add data*. - +To install the web logs sample data set, refer to <>. [float] === Step 2: Index Combined Statistical Area (CSA) regions @@ -46,7 +41,7 @@ To get the CSA boundary data: . Go to the https://www.census.gov/geographies/mapping-files/time-series/geo/carto-boundary-file.html[Census Bureau’s website] and download the `cb_2018_us_csa_500k.zip` file. . Uncompress the zip file. -. In Kibana, open the main menu, and click *Maps*. +. In Kibana, go to *Maps*. . Click *Create map*. . Click *Add layer*. . Click *Upload file*. @@ -71,7 +66,8 @@ image::maps/images/reverse-geocoding-tutorial/csa_regions.png[Map showing metro === Step 3: Reverse geocoding To visualize CSA regions by web log traffic, the web log traffic must contain a CSA region identifier. You'll use {es} {ref}/enrich-processor.html[enrich processor] to add CSA region identifiers to the web logs sample data set. You can skip this step if your source data already contains region identifiers. -. Open the main menu, and then click *Dev Tools*. +. Go to *Developer tools* using the navigation menu or the +<>. . In *Console*, create a {ref}/geo-match-enrich-policy-type.html[geo_match enrichment policy]: + [source,js] @@ -142,7 +138,7 @@ PUT kibana_sample_data_logs/_settings } ---------------------------------- -. Open the main menu, and click *Discover*. +. Go to *Discover*. . Set the data view to *Kibana Sample Data Logs*. . Open the <>, and set the time range to the last 30 days. . Scan through the list of *Available fields* until you find the `csa.GEOID` field. You can also search for the field by name. @@ -158,7 +154,7 @@ image::maps/images/reverse-geocoding-tutorial/discover_enriched_web_log.png[View === Step 4: Visualize Combined Statistical Area (CSA) regions by web traffic Now that our web traffic contains CSA region identifiers, you'll visualize CSA regions by web traffic. -. Open the main menu, and click *Maps*. +. Go to *Maps*. . Click *Create map*. . Click *Add layer*. . Click *Choropleth*. diff --git a/docs/maps/search.asciidoc b/docs/maps/search.asciidoc index bfd293aa2352..b094934bc6b4 100644 --- a/docs/maps/search.asciidoc +++ b/docs/maps/search.asciidoc @@ -85,7 +85,7 @@ Create filters from your map to focus in on just the data you want. *Maps* provi To filter your dashboard by your map bounds as you pan and zoom your map: -. Open the main menu, and then click *Dashboard*. +. Go to *Dashboards*. . Select your dashboard from the list or click *Create dashboard*. . If your dashboard does not have a map, add a map panel. . Click the gear icon image:maps/images/gear_icon.png[gear icon] to open the map panel menu. diff --git a/docs/osquery/manage-integration.asciidoc b/docs/osquery/manage-integration.asciidoc index 69cf505e724a..7d6131ce88bf 100644 --- a/docs/osquery/manage-integration.asciidoc +++ b/docs/osquery/manage-integration.asciidoc @@ -53,7 +53,8 @@ Any changes you make to `packs` from this field are not reflected in the UI on t While this allows you to use advanced Osquery functionality like pack discovery queries, you do lose the ability to manage packs defined this way from the Osquery *Packs* page. ========================= -. From the {kib} main menu, click *Fleet*, then the *Agent policies* tab. +. Go to *Fleet* using the navigation menu or the +<>, then open the *Agent policies* tab. . Click the name of the agent policy where you want to adjust the Osquery configuration. The configuration changes you make only apply to the policy you select. @@ -136,7 +137,8 @@ and Osquerybeat in the agent directory. Refer to the {fleet-guide}/installation- To get more details in the logs, change the agent logging level to debug: -. Open the main menu, and then select **Fleet**. +. Go to **Fleet** using the navigation menu or the +<>. . Select the agent that you want to debug. diff --git a/docs/osquery/osquery.asciidoc b/docs/osquery/osquery.asciidoc index 4f0859ac21b1..ebfd58c97337 100644 --- a/docs/osquery/osquery.asciidoc +++ b/docs/osquery/osquery.asciidoc @@ -36,7 +36,8 @@ view live and scheduled query results, but you cannot run live queries or edit. To inspect hosts, run a query against one or more agents or policies, then view the results. -. Open the main menu, and then click *Osquery*. +. Go to *Osquery* using the navigation menu or the +<>. . In the *Live queries* view, click **New live query**. . Choose to run a single query or a query pack. . Select one or more agents or groups to query. Start typing in the search field, diff --git a/docs/search/index.asciidoc b/docs/search/index.asciidoc index 4d2ee436327b..517503772d3c 100644 --- a/docs/search/index.asciidoc +++ b/docs/search/index.asciidoc @@ -10,7 +10,7 @@ The *Search* space in the {kib} UI contains the following GUI features: * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-application-overview.html[Search Applications] * https://www.elastic.co/guide/en/elasticsearch/reference/current/behavioral-analytics-overview.html[Behavioral Analytics] * <> -* <> +* <> * Dev Tools <> [float] diff --git a/docs/search/search-ai-assistant/images/ai-assistant-button.png b/docs/search/search-ai-assistant/images/ai-assistant-button.png new file mode 100644 index 000000000000..640d81e32d46 Binary files /dev/null and b/docs/search/search-ai-assistant/images/ai-assistant-button.png differ diff --git a/docs/search/search-ai-assistant/images/ai-assistant-welcome-chat.png b/docs/search/search-ai-assistant/images/ai-assistant-welcome-chat.png new file mode 100644 index 000000000000..972ad53599c8 Binary files /dev/null and b/docs/search/search-ai-assistant/images/ai-assistant-welcome-chat.png differ diff --git a/docs/search/search-ai-assistant/index.asciidoc b/docs/search/search-ai-assistant/index.asciidoc index b4013d9ef0ce..146dd22f2ff5 100644 --- a/docs/search/search-ai-assistant/index.asciidoc +++ b/docs/search/search-ai-assistant/index.asciidoc @@ -1,5 +1,143 @@ [role="xpack"] -[[search-assistant]] -== Search AI Assistant +[[search-ai-assistant]] +== AI Assistant -(coming in 8.16.0) \ No newline at end of file +[TIP] +==== +Don't confuse AI Assistant with <>! Use Playground to chat with your data, test and tweak different {es} queries in the Playground UI, and download the code to integrate into your own RAG application. + +Use AI Assistant to get help with Elasticsearch and Kibana tasks directly in the UI. +==== + +.Observability use cases +**** +Refer to the {observability-guide}/obs-ai-assistant.html[Observability documentation] for more information on how to use AI Assistant in Observability contexts. +**** + +*AI Assistant for Observability and Search* uses generative AI to help you with a variety of tasks related to Elasticsearch and Kibana, including: + +1. *Constructing Queries*: Assists you in building queries to search and analyze your data. +2. *Indexing Data*: Guides you on how to index data into Elasticsearch. +3. *Searching Data*: Helps you search for specific data within your Elasticsearch indices. +4. *Using Elasticsearch APIs*: Calls Elasticsearch APIs on your behalf if you need specific operations performed. +5. *Generating Sample Data*: Helps you create sample data for testing and development purposes. +6. *Visualizing and Analyzing Data*: Assists you in creating visualizations and analyzing your data using Kibana. +7. *Explaining ES|QL*: Explains how ES|QL works and help you convert queries from other languages to {ref}/esql.html[ES|QL.] + +[discrete] +[[ai-assistant-requirements]] +=== Requirements + +To use AI Assistant in *Search* contexts, you must have the following: + +* Elastic Stack version 8.16.0, or an Elasticsearch Serverless project. +* A <> to connect to a LLM provider, or a local model. +** You need an account with a third-party generative AI provider, which AI Assistant uses to generate responses, or else you need to host your own local model. +** To set up AI Assistant, you need the `Actions and Connectors : All` <>. +* To use AI Assistant, you need at least the `Elastic AI Assistant : All` and `Actions and Connectors : Read` <>. +* AI Assistant requires {ml-docs}/ml-nlp-elser.html[ELSER], Elastic's proprietary semantic search model. + +[discrete] +[[ai-assistant-data-information]] +=== Your data and AI Assistant + +Elastic does not use customer data for model training. This includes anything you send the model, such as alert or event data, detection rule configurations, queries, and prompts. However, any data you provide to AI Assistant will be processed by the third-party provider you chose when setting up the generative AI connector as part of the assistant setup. + +Elastic does not control third-party tools, and assumes no responsibility or liability for their content, operation, or use, nor for any loss or damage that may arise from your using such tools. Please exercise caution when using AI tools with personal, sensitive, or confidential information. Any data you submit may be used by the provider for AI training or other purposes. There is no guarantee that the provider will keep any information you provide secure or confidential. You should familiarize yourself with the privacy practices and terms of use of any generative AI tools prior to use. + +[discrete] +[[ai-assistant-using]] +=== Using AI Assistant + +To open AI Assistant, select the **AI Assistant** button in the top toolbar in the UI. +You can also use the global search field in the UI to find AI Assistant. +// <> +// TODO link will be available once https://github.com/elastic/kibana/pull/199352 is merged. + +[role="screenshot"] +image::images/ai-assistant-button.png[AI Assistant button,50] + +This opens the AI Assistant chat interface flyout. + +[role="screenshot] +image::images/ai-assistant-welcome-chat.png[AI Assistant Welcome chat,450] + +You can get started by selecting *✨ Suggest* to get some example prompts, or by typing into the chat field. + +[discrete] +[[ai-assistant-add-custom-data]] +=== Add data to the AI Assistant knowledge base + +[NOTE] +==== +This functionality is not available on Elastic Cloud Serverless projects. +==== + +You can improve the relevance of AI Assistant’s responses by indexing your own data into AI Assistant's knowledge base. +AI Assistant uses {ml-docs}/ml-nlp-elser.html[ELSER], Elastic's proprietary semantic search model, to power its search capabilities. + +[discrete] +[[search-ai-assistant-use-the-ui]] +==== Use the UI + +To add external data to the knowledge base in UI: + +. In the AI Assistant UI, select the **Settings** icon: `⋮`. +. Under *Actions*, click **Manage knowledge base**. +. Click the **New entry** button, and choose either: ++ +** **Single entry**: Write content for a single entry in the UI. +** **Bulk import**: Upload a newline delimited JSON (`ndjson`) file containing a list of entries to add to the knowledge base. +Each object should conform to the following format: ++ +[source,json] +---- +{ + "id": "a_unique_human_readable_id", + "text": "Contents of item", +} +---- + +[discrete] +[[observability-ai-assistant-add-data-to-kb]] +==== Use Search connectors + +// Will be updated to mention reindex option for arbitrary indices +// Need to consolidate docs with obs team first + +[NOTE] +==== +This functionality is not available on Elastic Cloud Serverless projects. +==== + +You can ingest external data (GitHub issues, Markdown files, Jira tickets, text files, etc.) into {es} using {ref}/es-connectors.html[Search Connectors]. Connectors sync third party data sources to {es}. + +Supported service types include {ref}/es-connectors-github.html[GitHub], {ref}/es-connectors-slack.html[Slack], {ref}/es-connectors-jira.html[Jira], and more. These can be Elastic managed or self-managed on your own infrastructure. + +To create a connector and make its content available to the AI Assistant knowledge base, follow these steps: + +. *In {kib} UI, go to _Search -> Content -> Connectors_ and follow the instructions to create a new connector.* ++ +For example, if you create a {ref}/es-connectors-github.html[GitHub connector] you must set a `name`, attach it to a new or existing `index`, add your `personal access token` and include the `list of repositories` to synchronize. ++ +TIP: Learn more about configuring and {ref}/es-connectors-usage.html[using connectors] in the Elasticsearch documentation. ++ +. *Create a pipeline and process the data with ELSER.* ++ +To process connector data using {ml-docs}/ml-nlp-elser.html[ELSER], you must create an *ML Inference Pipeline*: ++ +.. Open the previously created connector and select the *Pipelines* tab. +.. Select *Copy and customize* button at the `Unlock your custom pipelines` box. +.. Select *Add Inference Pipeline* button at the `Machine Learning Inference Pipelines` box. +.. Select *ELSER (Elastic Learned Sparse EncodeR)* ML model to add the necessary embeddings to the data. +.. Select the fields that need to be evaluated as part of the inference pipeline. +.. Test and save the inference pipeline and the overall pipeline. +. *Sync data.* ++ +Once the pipeline is set up, perform a *Full Content Sync* of the connector. The inference pipeline will process the data as follows: ++ +* As data comes in, the ELSER model processes the data, creating sparse embeddings for each document. +* If you inspect the ingested documents, you can see how the weights and tokens are added to the `predicted_value` field. +. *Confirm AI Assistant can access the index.* ++ +Ask the AI Assistant a specific question to confirm that the data is available for the AI Assistant knowledge base. diff --git a/docs/setup/configuring-reporting.asciidoc b/docs/setup/configuring-reporting.asciidoc index 4213cf38b639..61ef028d1504 100644 --- a/docs/setup/configuring-reporting.asciidoc +++ b/docs/setup/configuring-reporting.asciidoc @@ -48,9 +48,10 @@ NOTE: If you use the default settings, you can still create a custom role that g . Create the reporting role. -.. Open the main menu, then click *Stack Management*. +.. Go to the *Roles* management page using the navigation menu or the +<>. -.. Click *Roles > Create role*. +.. Click *Create role*. . Specify the role settings. @@ -86,9 +87,10 @@ NOTE: If the *Reporting* options for application features are unavailable, and t . Assign the reporting role to a user. -.. Open the main menu, then click *Stack Management*. +.. Go to the *Users* management page using the navigation menu or the +<>. -.. Click *Users*, then click the user you want to assign the reporting role to. +.. Select the user you want to assign the reporting role to. .. From the *Roles* dropdown, select *custom_reporting_user*. diff --git a/docs/setup/connect-to-elasticsearch.asciidoc b/docs/setup/connect-to-elasticsearch.asciidoc index f5c8ce3e732f..f6e6c71e25fb 100644 --- a/docs/setup/connect-to-elasticsearch.asciidoc +++ b/docs/setup/connect-to-elasticsearch.asciidoc @@ -6,8 +6,7 @@ which are pre-packaged assets that are available for a wide array of popular services and platforms. With integrations, you can add monitoring for logs and metrics, protect systems from security threats, and more. -All integrations are available in a single view, and -{kib} guides you there from the *Welcome* screen, home page, and main menu. +All integrations are available in a single view on the **Integrations** page. [role="screenshot"] image::images/add-integration.png[Integrations page from which you can choose integrations to start collecting and analyzing data] diff --git a/docs/upgrade-notes.asciidoc b/docs/upgrade-notes.asciidoc index 98f7feeac2d6..a0c2d6c1afcc 100644 --- a/docs/upgrade-notes.asciidoc +++ b/docs/upgrade-notes.asciidoc @@ -1432,6 +1432,35 @@ The `/agent_status` Fleet API now returns the following statuses: * `active` — All active ==== +[discrete] +[[kibana-150267]] +.Deprecated Saved objects APIs. (8.7) +[%collapsible] +==== +*Details* + +The following saved objects APIs have been deprecated. + +[source,text] +-- +/api/saved_objects/{type}/{id} +/api/saved_objects/resolve/{type}/{id} +/api/saved_objects/{type}/{id?} +/api/saved_objects/{type}/{id} +/api/saved_objects/_find +/api/saved_objects/{type}/{id} +/api/saved_objects/_bulk_get +/api/saved_objects/_bulk_create +/api/saved_objects/_bulk_resolve +/api/saved_objects/_bulk_update +/api/saved_objects/_bulk_delete +-- + +For more information, refer to ({kibana-pull}150267[#150267]). + +*Impact* + +Use dedicated public APIs instead, for example use <> to manage Data Views. +==== + [discrete] [[deprecation-119494]] .Updates Fleet API to improve consistency. (8.0) @@ -1696,19 +1725,16 @@ When you create *Lens* visualization, the default for the *Legend width* is now [discrete] [[deprecation-192003]] -* Deprecated the Observability AI Assistant specific advanced setting `observability:aiAssistantLogsIndexPattern`. (8.16) +.Deprecated the Observability AI Assistant specific advanced setting `observability:aiAssistantLogsIndexPattern`. (8.16) [%collapsible] ==== *Details* + The Observability AI Assistant specific advanced setting for Logs index patterns `observability:aiAssistantLogsIndexPattern` is deprecated and no longer used. The AI Assistant will now use the existing **Log sources** setting `observability:logSources` instead. For more information, refer to ({kibana-pull}192003[#192003]). - -//*Impact* + -//!!TODO!! ==== [discrete] [[deprecation-194519]] -* The Logs Stream was hidden by default in favor of the Logs Explorer app. (8.16) +.The Logs Stream was hidden by default in favor of the Logs Explorer app. (8.16) [%collapsible] ==== *Details* + diff --git a/docs/user/canvas.asciidoc b/docs/user/canvas.asciidoc index e7b4fdaf2092..21803b90034a 100644 --- a/docs/user/canvas.asciidoc +++ b/docs/user/canvas.asciidoc @@ -43,7 +43,8 @@ To create workpads, you must meet the minimum requirements. * Make sure you have sufficient privileges to create and save workpads. When the read-only indicator appears, you have insufficient privileges, and the options to create and save workpads are unavailable. For more information, refer to <>. -To open *Canvas*, open the main menu, then click *Canvas*. +You can open *Canvas* using the navigation menu or the +<>. [float] [[start-with-a-blank-workpad]] @@ -175,7 +176,7 @@ To share workpads with a larger audience, click *Share* in the toolbar. For deta [[export-single-workpad]] == Export workpads -Want to export multiple workpads? Go to the *Canvas* home page, select the workpads you want to export, then click *Export*. +Want to export multiple workpads? Go to the *Canvas* page, select the workpads you want to export, then click *Export*. -- @@ -185,8 +186,6 @@ include::{kibana-root}/docs/canvas/canvas-present-workpad.asciidoc[] include::{kibana-root}/docs/canvas/canvas-tutorial.asciidoc[] -include::{kibana-root}/docs/canvas/canvas-expression-lifecycle.asciidoc[] - include::{kibana-root}/docs/canvas/canvas-function-reference.asciidoc[] include::{kibana-root}/docs/canvas/canvas-tinymath-functions.asciidoc[] diff --git a/docs/user/dashboard/aggregation-based.asciidoc b/docs/user/dashboard/aggregation-based.asciidoc index 9098ea626529..f27d60928e6f 100644 --- a/docs/user/dashboard/aggregation-based.asciidoc +++ b/docs/user/dashboard/aggregation-based.asciidoc @@ -140,13 +140,9 @@ a bar chart that displays the top five log traffic sources for every three hours Add the sample web logs data that you'll use to create the bar chart, then create the dashboard. -. On the home page, click *Try sample data*. +. <>. -. Click *Other sample data sets*. - -. On the *Sample web logs* card, click *Add data*. - -. Open the main menu, then click *Dashboard*. +. Go to *Dashboards*. . On the *Dashboards* page, click *Create dashboard*. diff --git a/docs/user/dashboard/create-visualizations.asciidoc b/docs/user/dashboard/create-visualizations.asciidoc index 5115677a4f51..815f46d5711e 100644 --- a/docs/user/dashboard/create-visualizations.asciidoc +++ b/docs/user/dashboard/create-visualizations.asciidoc @@ -213,7 +213,7 @@ You can then **Save** and add it to an existing or a new dashboard using the sav . From your dashboard, select **Add panel**. . Choose **ES|QL** under **Visualizations**. An ES|QL editor appears and lets you configure your query and its associated visualization. The **Suggestions** panel can help you find alternative ways to configure the visualization. + -TIP: Check the link:esql-language.html[ES|QL reference] to get familiar with the syntax and optimize your query. +TIP: Check the link:{ref}/esql-language.html[ES|QL reference] to get familiar with the syntax and optimize your query. . When editing your query or its configuration, run the query to update the preview of the visualization. + image:https://images.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blt69dcceb4f1e12bc1/66c752d6aff77d384dc44209/edit-esql-visualization.gif[Previewing an ESQL visualization] @@ -232,7 +232,7 @@ The Maps editor has extensive documentation. For your reading comfort, we have m . From your dashboard, select **Add panel**. . Choose **Field statistics** under **Visualizations**. An ES|QL editor appears and lets you configure your query with the fields and information that you want to show. + -TIP: Check the link:esql-language.html[ES|QL reference] to get familiar with the syntax and optimize your query. +TIP: Check the link:{ref}/esql-language.html[ES|QL reference] to get familiar with the syntax and optimize your query. . When editing your query or its configuration, run the query to update the preview of the visualization. + image:https://images.contentstack.io/v3/assets/bltefdd0b53724fa2ce/blte2b1371159f5b9ff/66fc6ca13804eb2532b20727/field-statistics-preview-8.16.0.gif[Editing a field statistics dashboard panel and running the query to update the preview] @@ -289,7 +289,8 @@ To personalize your dashboards, add your own logos and graphics with the *Image* [role="screenshot"] image::images/dashboard_addImageEditor_8.7.0.png[Add image editor] -To manage your uploaded image files, open the main menu, then click *Stack Management > Kibana > Files*. +To manage your uploaded image files, go to the *Files* management page using the navigation menu or the +<>. [WARNING] diff --git a/docs/user/dashboard/lens-advanced.asciidoc b/docs/user/dashboard/lens-advanced.asciidoc index 88dbe958b146..5107172c40b3 100644 --- a/docs/user/dashboard/lens-advanced.asciidoc +++ b/docs/user/dashboard/lens-advanced.asciidoc @@ -16,15 +16,9 @@ Before you begin, you should be familiar with the <>. Add the sample eCommerce data, and create and set up the dashboard. -. On the home page, click *Try sample data*. +. <>. -. Expand *Other sample data sets*. - -. On the *Sample eCommerce orders* card, click *Add data*. - -Create the dashboard where you'll display the visualization panels. - -. Open the main menu, then click *Dashboards*. +. Go to *Dashboards*. . On the *Dashboards* page, click *Create dashboard*. diff --git a/docs/user/dashboard/lens.asciidoc b/docs/user/dashboard/lens.asciidoc index 8623b8c3ca10..3c2a120d167d 100644 --- a/docs/user/dashboard/lens.asciidoc +++ b/docs/user/dashboard/lens.asciidoc @@ -96,13 +96,37 @@ All columns that belong to the same layer pane group are sorted in the table. * *Text alignment* — Aligns the values in the cell to the *Left*, *Center*, or *Right*. +* *Color by value* — Applies color to the cell or text values. To change the color, click the *Edit colors* icon. + * *Hide column* — Hides the column for the field. * *Directly filter on click* — Turns column values into clickable links that allow you to filter or drill down into the data. * *Summary row* — Adds a row that displays the summary value. When specified, allows you to enter a *Summary label*. -* *Color by value* — Applies color to the cell or text values. To change the color, click *Edit*. +[float] +[[assign-colors-to-terms]] +===== Assign colors to terms + +preview::[] + +For term-based metrics, assign a color to each term with color mapping. + +. Create a custom table. + +. In the layer pane, select a *Rows* or *Metrics* field. + +. In the *Color by value* option, select *Cell* or *Text*. + +. Click the *Edit colors* icon. + +. Toggle the button to use the Color Mapping feature. + +. Select a color palette and mode. + +. Click *Add assignment* to assign a color to a specific term, or click *Add all unassigned terms* to assign colors to all terms. Assigning colors to dates is unsupported. + +. Configure color assignments. You can also select whether unassigned terms should be mapped to the selected color palette or a single color. [float] [[drag-and-drop-keyboard-navigation]] diff --git a/docs/user/dashboard/timelion.asciidoc b/docs/user/dashboard/timelion.asciidoc index 27222e6a40e8..000cad3bdbc1 100644 --- a/docs/user/dashboard/timelion.asciidoc +++ b/docs/user/dashboard/timelion.asciidoc @@ -88,7 +88,7 @@ Set up Metricbeat, then create the dashboard. . To set up Metricbeat, go to {metricbeat-ref}/metricbeat-installation-configuration.html[Metricbeat quick start: installation and configuration] -. From {kib}, open the main menu, then click *Dashboard*. +. Go to *Dashboards*. . On the *Dashboards* page, click *Create dashboard*. diff --git a/docs/user/dashboard/tutorial-create-a-dashboard-of-lens-panels.asciidoc b/docs/user/dashboard/tutorial-create-a-dashboard-of-lens-panels.asciidoc index db0717522d92..4d299ba95129 100644 --- a/docs/user/dashboard/tutorial-create-a-dashboard-of-lens-panels.asciidoc +++ b/docs/user/dashboard/tutorial-create-a-dashboard-of-lens-panels.asciidoc @@ -18,15 +18,9 @@ Before you begin, you should be familiar with the <>. Add the sample web logs data, and create and set up the dashboard. -. On the home page, click *Try sample data*. +. <>. -. Expand *Other sample data sets*. - -. On the *Sample web logs* card, click *Add data*. - -Create the dashboard where you'll display the visualization panels. - -. Open the main menu, then click *Dashboards*. +. Go to *Dashboards*. . Click *Create dashboard*. diff --git a/docs/user/dashboard/tutorials.asciidoc b/docs/user/dashboard/tutorials.asciidoc index 6c25fd221fe2..e7752279ba47 100644 --- a/docs/user/dashboard/tutorials.asciidoc +++ b/docs/user/dashboard/tutorials.asciidoc @@ -2,7 +2,7 @@ Learn more about building dashboards and creating visualizations with the following tutorials. -These tutorials use sample data available in {kib} as a way to get started more easily, but you can apply and adapt these instructions to your own data as well. +These tutorials use <> available in {kib} as a way to get started more easily, but you can apply and adapt these instructions to your own data as well. include::tutorial-create-a-dashboard-of-lens-panels.asciidoc[] diff --git a/docs/user/dashboard/vega.asciidoc b/docs/user/dashboard/vega.asciidoc index cbb1f5dbf8cd..4ae9c994a54b 100644 --- a/docs/user/dashboard/vega.asciidoc +++ b/docs/user/dashboard/vega.asciidoc @@ -40,13 +40,9 @@ As you edit the specs, work in small steps, and frequently save your work. Small Before starting, add the eCommerce sample data that you'll use in your spec, then create the dashboard. -. On the home page, click *Try sample data*. +. <>. -. Click *Other sample data sets*. - -. On the *Sample eCommerce orders* card, click *Add data*. - -. Open the main menu, then click *Dashboard*. +. Go to *Dashboards*. . On the *Dashboards* page, click *Create dashboard*. @@ -90,7 +86,8 @@ To check your work, open and use the <> on a separate . Open {kib} on a new tab. -. Open the main menu, then click *Dev Tools*. +. Go to the *Developer tools* page using the navigation menu or the +<>. . On the *Console* editor, enter the aggregation, then click *Click to send request*: diff --git a/docs/user/discover.asciidoc b/docs/user/discover.asciidoc index ddd06b06c9cd..7cab19889f27 100644 --- a/docs/user/discover.asciidoc +++ b/docs/user/discover.asciidoc @@ -8,6 +8,7 @@ What pages on your website contain a specific word or phrase? What events were logged most recently? What processes take longer than 500 milliseconds to respond? +[[save-your-search]] With *Discover*, you can quickly search and filter your data, get information about the structure of the fields, and display your findings in a visualization. You can also customize and save your searches and place them on a dashboard. @@ -16,331 +17,10 @@ You can also customize and save your searches and place them on a dashboard. image::images/hello-field.png[A view of the Discover app] -[float] -=== Explore and query your data - -This tutorial shows you how to use *Discover* to search large amounts of -data and understand what’s going on at any given time. - -You’ll learn to: - -- **Select** data for your exploration, set a time range for that data, -search it with the {kib} Query Language, and filter the results. -- **Explore** the details of your data, view individual documents, and create tables -that summarize the contents of the data. -- **Present** your findings in a visualization. - -At the end of this tutorial, you’ll be ready to start exploring with your own -data in *Discover*. - -*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]. -- You must have data in {es}. This tutorial uses the -<>, but you can use your own data. -- You should have an understanding of {ref}/documents-indices.html[{es} documents and indices] -and <>. - - -[float] -[[find-the-data-you-want-to-use]] -=== Find your data - -Tell {kib} where to find the data you want to explore, and then specify the time range in which to view that data. - -. Open the main menu, and select **Discover**. - -. Select the data you want to work with. -+ -{kib} uses a <> to tell it where to find -your {es} data. -To view the ecommerce sample data, open the {data-source} menu, and then select **Kibana Sample Data Ecommerce**. -+ -[role="screenshot"] -image::images/discover-data-view.png[How to set the {data-source} in Discover, width="40%"] - -+ -To create a data view for your own data, -click *Create a data view*. -For details, refer to <> - -. Adjust the <> to view data for the *Last 7 days*. -+ -The range selection is based on the default time field in your data. -If you are using the sample data, this value was set when you added the data. -If you are using your own data, and it does not have a time field, the range selection is not available. - -. To view the count of documents for a given time in the specified range, -click and drag the mouse over the chart. - -[float] -[[explore-fields-in-your-data]] -=== Explore the fields in your data - -**Discover** includes a table -that shows all the documents that match your search. -By default, the document table includes a column for the time field and a column that lists all other fields in the document. -You’ll modify the document table to display your fields of interest. - -. In the sidebar, enter `ma` in the search field to find the `manufacturer` field. -+ -[role="screenshot"] -image:images/discover-sidebar-available-fields.png[Fields list that displays the top five search results, width=50%] -+ -NOTE: You can use wildcards in field searches. For example, `goe*dest` finds `geo.dest` and `geo.src.dest`. - -. In the *Available fields* list, click `manufacturer` to view its most popular values. -+ -**Discover** shows the top 10 values and the number of records used to calculate those values. - -. Click image:images/add-icon.png[Add icon] to toggle the field into the document table. -You can also drag the field from the *Available fields* list into the document table. -+ -[role="screenshot"] -image::images/discover-add-icon.png[How to add a field as a column in the table, width="50%"] - -. Find the `customer_first_name` and `customer_last_name` fields and add -them to the document table. Your table should look similar to this: -+ -[role="screenshot"] -image:images/document-table.png[Document table with fields for manufacturer, customer_first_name, and customer_last_name] - - -. Optionally try out these actions: -+ -* To rearrange the table columns, click a -column header, and then select *Move left* or *Move right*. -+ -* To copy the name or values in a column to the clipboard, click the column header and select the desired **Copy** option. -+ -* To view more of the document table, -click -image:images/chart-icon.png[icon button for opening Show/Hide chart menu, width=24px] -to open the *Chart options* menu, -and then select *Hide chart*. -+ -* For keyboard shortcuts on the document table, click -image:images/keyboard-shortcut-icon.png[icon button for opening list of keyboard shortcuts, width=24px]. -+ -* To set the row height to one or more lines, or automatically -adjust the height to fit the contents, click -image:images/row-height-icon.png[icon to open the Row height pop-up, width=24px]. -+ -* To toggle the table in and out of fullscreen mode, click the fullscreen icon -image:images/fullscreen-icon.png[icon to display the document table in fullscreen mode]. - - - - - - -[float] -[[add-field-in-discover]] -=== Add a field to your {data-source} - -What happens if you forgot to define an important value as a separate field? Or, what if you -want to combine two fields and treat them as one? This is where {ref}/runtime.html[runtime fields] come into play. -You can add a runtime field to your {data-source} from inside of **Discover**, -and then use that field for analysis and visualizations, -the same way you do with other fields. - -. In the sidebar, click *Add a field*. - -. In the *Create field* form, enter `hello` for the name. - -. Turn on *Set value*. - -. Define the script using the Painless scripting language. Runtime fields require an `emit()`. -+ -```ts -emit("Hello World!"); -``` - -. Click *Save*. - -. In the sidebar, search for the *hello* field, and then add it to the document table. -+ -[role="screenshot"] -image:images/hello-field.png[hello field in the document tables] - -. Create a second field named `customer` that combines customer last name and first initial. -+ -```ts -String str = doc['customer_first_name.keyword'].value; -char ch1 = str.charAt(0); -emit(doc['customer_last_name.keyword'].value + ", " + ch1); -``` -. Remove `customer_first_name` and `customer_last_name` from the document table, and then add `customer`. -+ -[role="screenshot"] -image:images/customer.png[Customer last name, first initial in the document table] -+ -For more information on adding fields and Painless scripting language examples, -refer to <>. - - -[float] -[[search-in-discover]] -=== Search your data - -One of the unique capabilities of **Discover** is the ability to combine -free text search with filtering based on structured data. -To search all fields, enter a simple string in the query bar. - -[role="screenshot"] -image:images/discover-search-field.png[Search field in Discover] - - -To search particular fields and -build more complex queries, use the <>. -As you type, KQL prompts you with the fields you can search and the operators -you can use to build a structured query. - -Search the ecommerce data for documents where the country matches US: - -. Enter `g`, and then select *geoip.country_iso_code*. -. Select *:* for equals some value and *US*, and then click the refresh button or press the Enter key. -. For a more complex search, try: -+ -```ts -geoip.country_iso_code : US and products.taxless_price >= 75 -``` - -[float] -[[filter-in-discover]] -=== Filter your data - -Whereas the query defines the set of documents you are interested in, -filters enable you to zero in on subsets of those documents. -You can filter results to include or exclude specific fields, filter for a value in a range, -and more. - -Exclude documents where day of week is not Wednesday: - -. Click image:images/add-icon.png[Add icon] next to the query bar. -. In the *Add filter* pop-up, set the field to *day_of_week*, the operator to *is not*, -and the value to *Wednesday*. -+ -[role="screenshot"] -image:images/discover-add-filter.png[Add filter dialog in Discover] - -. Click **Add filter**. -. Continue your exploration by adding more filters. -. To remove a filter, -click the close icon (x) next to its name in the filter bar. - -[float] -[[look-inside-a-document]] -=== Look inside a document - -Dive into an individual document to view its fields and the documents -that occurred before and after it. - -. In the document table, click the expand icon -image:images/expand-icon-2.png[double arrow icon to open a flyout with the document details] -to show document details. -+ -[role="screenshot"] -image:images/document-table-expanded.png[Table view with document expanded] - -. Scan through the fields and their values. If you find a field of interest, -hover your mouse over the *Actions* column for filters and other options. - -. To create a view of the document that you can bookmark and share, click **Single document**. - -. To view documents that occurred before or after the event you are looking at, click -**Surrounding documents**. - - - -[float] -[[save-your-search]] -=== Save your search for later use - -Save your search so you can use it later, generate a CSV report, or use it to create visualizations, dashboards, and Canvas workpads. -Saving a search saves the query text, filters, -and current view of *Discover*, including the columns selected in -the document table, the sort order, and the {data-source}. - -. In the toolbar, click **Save**. - -. Give your search a title. - -. Optionally store <> and the time range with the search. - -. Click **Save**. - -[float] -=== Visualize your findings -If a field can be {ref}/search-aggregations.html[aggregated], you can quickly -visualize it from **Discover**. - -. In the sidebar, find and then click `day_of_week`. -+ -[role="screenshot"] -image:images/discover-day-of-week.png[Top values for the day_of_week field, plus Visualize button, width=50%] - - -. In the popup, click **Visualize**. -+ -{kib} creates a visualization best suited for this field. - -. From the *Available fields* list, drag and drop `manufacturer.keyword` onto the workspace. -+ -[role="screenshot"] -image:images/discover-from-visualize.png[Visualization that opens from Discover based on your data] - -. Save your visualization for use on a dashboard. -+ -For geo point fields (image:images/geoip-icon.png[Geo point field icon, width=20px]), -if you click **Visualize**, -your data appears in a map. -+ -[role="screenshot"] -image:images/discover-maps.png[Map containing documents] - -[float] -[[share-your-findings]] -=== Share your findings - -To share your findings with a larger audience, click *Share* in the *Discover* toolbar. -For detailed information about the sharing options, refer to <>. - -[float] -[[alert-from-Discover]] -=== Generate alerts - -From *Discover*, you can create a rule to periodically -check when data goes above or below a certain threshold within a given time interval. - -. Ensure that your data view, -query, and filters fetch the data for which you want an alert. -. In the toolbar, click *Alerts > Create search threshold rule*. -+ -The *Create rule* form is pre-filled with the latest query sent to {es}. -. <> and <>. - -. Click *Save*. - -For more about this and other rules provided in {alert-features}, go to <>. - - -[float] -=== What’s next? - -* <>. - -* <>. - -* <> to better meet your needs. - -[float] -=== Troubleshooting - -* {blog-ref}troubleshooting-guide-common-issues-kibana-discover-load[Learn how to resolve common issues with Discover.] +-- +include::{kibana-root}/docs/discover/get-started-discover.asciidoc[] --- include::{kibana-root}/docs/discover/document-explorer.asciidoc[] include::{kibana-root}/docs/discover/search-for-relevance.asciidoc[] diff --git a/docs/user/graph/getting-started.asciidoc b/docs/user/graph/getting-started.asciidoc index 03274bec7671..40d23ba249fd 100644 --- a/docs/user/graph/getting-started.asciidoc +++ b/docs/user/graph/getting-started.asciidoc @@ -9,7 +9,7 @@ You must index data into {es} before you can create a graph. [[exploring-connections]] === Graph a data connection -. Open the main menu, then click *Graph*. +. Go to *Graph*. + If this is your first graph, follow the prompts to create it. For subsequent graphs, click *New*. diff --git a/docs/user/graph/index.asciidoc b/docs/user/graph/index.asciidoc index 5e7b689b8d8f..d6d30dfa8068 100644 --- a/docs/user/graph/index.asciidoc +++ b/docs/user/graph/index.asciidoc @@ -71,7 +71,7 @@ affecting the cluster. Use *Graph* to reveal the relationships in your data. -. Open the main menu, and then click *Graph*. +. Go to *Graph*. + If you're new to {kib}, and don't yet have any data, follow the link to add sample data. This example uses the {kib} sample web logs data set. diff --git a/docs/user/images/hello-field.png b/docs/user/images/hello-field.png new file mode 100644 index 000000000000..8aee22bf2a84 Binary files /dev/null and b/docs/user/images/hello-field.png differ diff --git a/docs/user/introduction.asciidoc b/docs/user/introduction.asciidoc index 48c9dfd91c9c..cd04da190eac 100644 --- a/docs/user/introduction.asciidoc +++ b/docs/user/introduction.asciidoc @@ -71,8 +71,7 @@ image::images/visualization-journey.png[User data analysis journey] | *1* | *Add data.* The best way to add data to the Elastic Stack is to use one of our many <>. -Alternatively, you can add a sample data set or upload a file. All three options are available -on the home page. +On the **Integrations** page, you can also find options to add sample data sets or to upload a file. | *2* | *Explore.* With <>, you can search your data for hidden diff --git a/docs/user/monitoring/monitoring-elastic-agent.asciidoc b/docs/user/monitoring/monitoring-elastic-agent.asciidoc index 33899e69ba26..2be91f08cdc0 100644 --- a/docs/user/monitoring/monitoring-elastic-agent.asciidoc +++ b/docs/user/monitoring/monitoring-elastic-agent.asciidoc @@ -27,7 +27,7 @@ in the {ref}/monitoring-production.html[{es} monitoring documentation]. To collect {kib} monitoring data, add a {kib} integration to an {agent} and deploy it to the host where {kib} is running. -. Go to the {kib} home page and click **Add integrations**. +. Go to the **Integrations** page. + NOTE: If you're using a monitoring cluster, use the {kib} instance connected to the monitoring cluster. diff --git a/docs/user/monitoring/monitoring-kibana.asciidoc b/docs/user/monitoring/monitoring-kibana.asciidoc index 7f060d7aab73..65c5bdf868b9 100644 --- a/docs/user/monitoring/monitoring-kibana.asciidoc +++ b/docs/user/monitoring/monitoring-kibana.asciidoc @@ -49,7 +49,8 @@ By default, if you are running {kib} locally, go to `http://localhost:5601/`. If {security-features} are enabled, log in. -- -... Open the main menu, then click *Stack Monitoring*. If data collection is +... Go to the *Stack Monitoring* page using the +<>. If data collection is disabled, you are prompted to turn it on. ** From the Console or command line, set `xpack.monitoring.collection.enabled` diff --git a/docs/user/monitoring/viewing-metrics.asciidoc b/docs/user/monitoring/viewing-metrics.asciidoc index 0aaf7ad6bd33..342a8da76cc3 100644 --- a/docs/user/monitoring/viewing-metrics.asciidoc +++ b/docs/user/monitoring/viewing-metrics.asciidoc @@ -86,7 +86,8 @@ By default, if you are running {kib} locally, go to `http://localhost:5601/`. If the Elastic {security-features} are enabled, log in. -- -. Open the main menu, then click *Stack Monitoring*. +. Go to the *Stack Monitoring* page using the +<>. + -- If data collection is disabled, you are prompted to turn on data collection. diff --git a/docs/user/reporting/automating-report-generation.asciidoc b/docs/user/reporting/automating-report-generation.asciidoc index f2102e7c0e2d..9587674b59e6 100644 --- a/docs/user/reporting/automating-report-generation.asciidoc +++ b/docs/user/reporting/automating-report-generation.asciidoc @@ -12,7 +12,7 @@ Create the POST URL that triggers a report to generate PDF and CSV reports. To create the POST URL for PDF reports: -. Open the main menu, then click *Dashboard*, *Visualize Library*, or *Canvas*. +. Go to *Dashboards*, *Visualize Library*, or *Canvas*. . Open the dashboard, visualization, or **Canvas** workpad you want to view as a report. @@ -24,7 +24,7 @@ To create the POST URL for PDF reports: To create the POST URL for CSV reports: -. Open the main menu, then click *Discover*. +. Go to *Discover*. . Open the saved search you want to share. diff --git a/docs/user/reporting/index.asciidoc b/docs/user/reporting/index.asciidoc index 5f09ed6907c1..ed4fef61026f 100644 --- a/docs/user/reporting/index.asciidoc +++ b/docs/user/reporting/index.asciidoc @@ -54,7 +54,7 @@ In the following dashboard, the shareable container is highlighted: [role="screenshot"] image::user/reporting/images/shareable-container.png["Shareable Container"] -. Open the main menu, then open the saved search, dashboard, visualization, or workpad you want to share. +. Open the saved search, dashboard, visualization, or workpad you want to share. . From the toolbar, click *Share*, then select the report option. @@ -94,7 +94,7 @@ include::reporting-pdf-limitations.asciidoc[] Create and share JSON files for workpads. -. Open the main menu, then click *Canvas*. +. Go to *Canvas*. . Open the workpad you want to share. @@ -118,7 +118,7 @@ change {kib} sizing, {ess-console}[edit the deployment]. beta[] Create and securely share static *Canvas* workpads on a website. To customize the behavior of the workpad on your website, you can choose to autoplay the pages or hide the workpad toolbar. -. Open the main menu, then click *Canvas*. +. Go to *Canvas*. . Open the workpad you want to share. @@ -140,7 +140,7 @@ Display your dashboards on an internal company website or personal web page with For information about granting access to embedded dashboards, refer to <>. -. Open the main menu, then open the dashboard you want to share. +. Open the dashboard you want to share. . Click *Share > Embed code*. diff --git a/docs/user/security/api-keys/index.asciidoc b/docs/user/security/api-keys/index.asciidoc index 2f9a0d337e3b..bbc5f2834c2c 100644 --- a/docs/user/security/api-keys/index.asciidoc +++ b/docs/user/security/api-keys/index.asciidoc @@ -13,7 +13,8 @@ You can use {kib} to manage your different API keys: * Cross-cluster API key: allows other clusters to connect to this cluster. * Managed API key: created and managed by Kibana to run background tasks. -To manage API keys, open the main menu, then click *Stack Management > Security > API Keys*. +To manage API keys, go to the *API Keys* management page using the navigation menu or the +<>. [role="screenshot"] image:images/api-keys.png["API Keys UI"] @@ -28,13 +29,15 @@ image:images/api-keys.png["API Keys UI"] * To create or update a *cross-cluster API key*, you must have the `manage_security` privilege and an Enterprise license. * To have a read-only view on the API keys, you must have access to the page and the `read_security` cluster privilege. -To manage roles, open the main menu, then click *Stack Management > Security > Roles*, or use the {api-kibana}/group/endpoint-roles[role APIs]. +To manage roles, go to the *Roles* management page using the navigation menu or the +<>, or use the {api-kibana}/group/endpoint-roles[role APIs]. [float] [[create-api-key]] === Create an API key -To create an API key, open the main menu, then click *Stack Management > Security > API Keys > Create API key*. +To create an API key, go to the *API Keys* management page using the navigation menu or the +<>, and select *Create API key*. [role="screenshot"] image:images/create-ccr-api-key.png["Create API Key UI"] @@ -48,7 +51,8 @@ Refer to the {ref}/security-api-create-cross-cluster-api-key.html[create cross-c [[udpate-api-key]] === Update an API key -To update an API key, open the main menu, click *Stack Management > Security > API Keys*, and then click on the name of the key. You cannot update the name or the type of API key. +To update an API key, go to the *API Keys* management page using the navigation menu or the +<>, and then click on the name of the key. You cannot update the name or the type of API key. Refer to the {ref}/security-api-update-api-key.html[update API key] documentation to learn more about updating user API keys. diff --git a/docs/user/security/index.asciidoc b/docs/user/security/index.asciidoc index 44d7c41391c3..3ea0245a2165 100644 --- a/docs/user/security/index.asciidoc +++ b/docs/user/security/index.asciidoc @@ -21,7 +21,8 @@ The `manage_security` cluster privilege is required to access all Security featu [float] === Users -To create and manage users, open the main menu, then click *Stack Management > Users*. +To create and manage users, go to the *Users* management page using the navigation menu or the +<>. You can also change their passwords and roles. For more information about authentication and built-in users, see {ref}/setting-up-authentication.html[Setting up user authentication]. @@ -29,7 +30,8 @@ authentication and built-in users, see [float] === Roles -To manage roles, open the main menu, then click *Stack Management > Roles*, or use +To manage roles, go to the *Roles* management page using the navigation menu or the +<>, or use the {api-kibana}/group/endpoint-roles[role APIs]. For more information on configuring roles for {kib}, see <>. For a more holistic overview of configuring roles for the entire stack, diff --git a/docs/user/security/role-mappings/index.asciidoc b/docs/user/security/role-mappings/index.asciidoc index df4ded4321c1..35de39e05223 100644 --- a/docs/user/security/role-mappings/index.asciidoc +++ b/docs/user/security/role-mappings/index.asciidoc @@ -8,7 +8,8 @@ describe which roles to assign to your users using a set of rules. Role mappings are required when authenticating via an external identity provider, such as Active Directory, Kerberos, PKI, OIDC, or SAML. Role mappings have no effect for users inside the `native` or `file` realms. -To manage your role mappings, open the main menu, then click *Stack Management > Role Mappings*. +You can find the *Role mappings* management page using the navigation menu or the +<>. With *Role mappings*, you can: @@ -27,7 +28,8 @@ The `manage_security` cluster privilege is required to manage Role Mappings. [float] === Create a role mapping -. Open the main menu, then click *Stack Management > Role Mappings*. +. Go to the *Role mappings* management page using the navigation menu or the +<>. . Click *Create role mapping*. . Give your role mapping a unique name, and choose which roles you wish to assign to your users. + diff --git a/docs/user/security/securing-kibana.asciidoc b/docs/user/security/securing-kibana.asciidoc index 98290bb093e4..0c05dd89ebec 100644 --- a/docs/user/security/securing-kibana.asciidoc +++ b/docs/user/security/securing-kibana.asciidoc @@ -65,10 +65,12 @@ the `elastic` user or other built-in users, run the . [[kibana-roles]]Create roles and users to grant access to {kib}. + -- -To manage privileges in {kib}, open the main menu, then click *Stack Management > Roles*. The built-in `kibana_admin` role will grant +To manage privileges in {kib}, go to the *Roles* management page using the navigation menu or the +<>. The built-in `kibana_admin` role will grant access to {kib} with administrator privileges. Alternatively, you can create additional roles that grant limited access to {kib}. -If you're using the default native realm with Basic Authentication, open the main menu, then click *Stack Management > Users* to create +If you're using the default native realm with Basic Authentication, go to the *Users* management page using the navigation menu or the +<> to create users and assign roles, or use the {es} {ref}/security-api.html#security-user-apis[user management APIs]. For example, the following creates a user named `jacknich` and assigns it the `kibana_admin` role: diff --git a/docs/user/security/tutorials/how-to-secure-access-to-kibana.asciidoc b/docs/user/security/tutorials/how-to-secure-access-to-kibana.asciidoc index d62ccebb0565..3b4e4b02af67 100644 --- a/docs/user/security/tutorials/how-to-secure-access-to-kibana.asciidoc +++ b/docs/user/security/tutorials/how-to-secure-access-to-kibana.asciidoc @@ -52,8 +52,8 @@ Let’s work through an example together. Consider a marketing analyst who wants Create a Marketing space for your marketing analysts to use. -. Open the main menu, and select **Stack Management**. -. Under **{kib}**, select **Spaces**. +. Go to the *Spaces* management page using the navigation menu or the +<>. . Click **Create a space**. . Give this space a unique name. For example: `Marketing`. . Click **Create space**. @@ -75,8 +75,8 @@ In this example, a marketing analyst will need: To create the role: -. Open the main menu, and select **Stack Management**. -. Under **Security**, select **Roles**. +. Go to the *Roles* management page using the navigation menu or the +<>. . Click **Create role**. . Give this role a unique name. For example: `marketing_dashboards_role`. . For this example, you want to store all marketing data in the `acme-marketing-*` set of indices. To grant this access, locate the **Index privileges** section and enter: diff --git a/examples/feature_flags_example/public/components/app.tsx b/examples/feature_flags_example/public/components/app.tsx index 432e7dc348ab..97f850b5dd47 100644 --- a/examples/feature_flags_example/public/components/app.tsx +++ b/examples/feature_flags_example/public/components/app.tsx @@ -8,24 +8,15 @@ */ import React from 'react'; -import { - EuiHorizontalRule, - EuiPageTemplate, - EuiTitle, - EuiText, - EuiLink, - EuiListGroup, - EuiListGroupItem, -} from '@elastic/eui'; +import { EuiHorizontalRule, EuiPageTemplate, EuiTitle, EuiText, EuiLink } from '@elastic/eui'; import type { CoreStart, FeatureFlagsStart } from '@kbn/core/public'; -import useObservable from 'react-use/lib/useObservable'; -import { - FeatureFlagExampleBoolean, - FeatureFlagExampleNumber, - FeatureFlagExampleString, -} from '../../common/feature_flags'; import { PLUGIN_NAME } from '../../common'; +import { + FeatureFlagsFullList, + FeatureFlagsReactiveList, + FeatureFlagsStaticList, +} from './feature_flags_list'; interface FeatureFlagsExampleAppDeps { featureFlags: FeatureFlagsStart; @@ -34,16 +25,6 @@ interface FeatureFlagsExampleAppDeps { } export const FeatureFlagsExampleApp = ({ featureFlags }: FeatureFlagsExampleAppDeps) => { - // Fetching the feature flags synchronously - const bool = featureFlags.getBooleanValue(FeatureFlagExampleBoolean, false); - const str = featureFlags.getStringValue(FeatureFlagExampleString, 'red'); - const num = featureFlags.getNumberValue(FeatureFlagExampleNumber, 1); - - // Use React Hooks to observe feature flags changes - const bool$ = useObservable(featureFlags.getBooleanValue$(FeatureFlagExampleBoolean, false)); - const str$ = useObservable(featureFlags.getStringValue$(FeatureFlagExampleString, 'red')); - const num$ = useObservable(featureFlags.getNumberValue$(FeatureFlagExampleNumber, 1)); - return ( <> @@ -67,22 +48,21 @@ export const FeatureFlagsExampleApp = ({ featureFlags }: FeatureFlagsExampleAppD .

- -

- The feature flags are: - - - -

-
- -

- The observed feature flags are: - - - -

-
+

Rendered separately

+

+ Each list are 2 different components, so only the reactive one is re-rendered when the + feature flag is updated and the static one keeps the value until the next refresh. +

+ + + +

Rendered together

+

+ `useObservable` causes a full re-render of the component, updating the{' '} + statically + evaluated flags as well. +

+
diff --git a/examples/feature_flags_example/public/components/feature_flags_list.tsx b/examples/feature_flags_example/public/components/feature_flags_list.tsx new file mode 100644 index 000000000000..73d653529586 --- /dev/null +++ b/examples/feature_flags_example/public/components/feature_flags_list.tsx @@ -0,0 +1,91 @@ +/* + * Copyright 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 { EuiListGroup, EuiListGroupItem } from '@elastic/eui'; +import React from 'react'; +import type { FeatureFlagsStart } from '@kbn/core-feature-flags-browser'; +import useObservable from 'react-use/lib/useObservable'; +import { + FeatureFlagExampleBoolean, + FeatureFlagExampleNumber, + FeatureFlagExampleString, +} from '../../common/feature_flags'; + +export interface FeatureFlagsListProps { + featureFlags: FeatureFlagsStart; +} + +export const FeatureFlagsStaticList = ({ featureFlags }: FeatureFlagsListProps) => { + // Fetching the feature flags synchronously + const bool = featureFlags.getBooleanValue(FeatureFlagExampleBoolean, false); + const str = featureFlags.getStringValue(FeatureFlagExampleString, 'red'); + const num = featureFlags.getNumberValue(FeatureFlagExampleNumber, 1); + + return ( + +

+ The feature flags are: + + + +

+
+ ); +}; + +export const FeatureFlagsReactiveList = ({ featureFlags }: FeatureFlagsListProps) => { + // Use React Hooks to observe feature flags changes + const bool$ = useObservable(featureFlags.getBooleanValue$(FeatureFlagExampleBoolean, false)); + const str$ = useObservable(featureFlags.getStringValue$(FeatureFlagExampleString, 'red')); + const num$ = useObservable(featureFlags.getNumberValue$(FeatureFlagExampleNumber, 1)); + + return ( + +

+ The observed feature flags are: + + + +

+
+ ); +}; + +export const FeatureFlagsFullList = ({ featureFlags }: FeatureFlagsListProps) => { + // Fetching the feature flags synchronously + const bool = featureFlags.getBooleanValue(FeatureFlagExampleBoolean, false); + const str = featureFlags.getStringValue(FeatureFlagExampleString, 'red'); + const num = featureFlags.getNumberValue(FeatureFlagExampleNumber, 1); + + // Use React Hooks to observe feature flags changes + const bool$ = useObservable(featureFlags.getBooleanValue$(FeatureFlagExampleBoolean, false)); + const str$ = useObservable(featureFlags.getStringValue$(FeatureFlagExampleString, 'red')); + const num$ = useObservable(featureFlags.getNumberValue$(FeatureFlagExampleNumber, 1)); + + return ( + <> + +

+ The feature flags are: + + + +

+
+ +

+ The observed feature flags are: + + + +

+
+ + ); +}; diff --git a/examples/feature_flags_example/tsconfig.json b/examples/feature_flags_example/tsconfig.json index bbd68332f3d3..77eb5d09ca85 100644 --- a/examples/feature_flags_example/tsconfig.json +++ b/examples/feature_flags_example/tsconfig.json @@ -20,5 +20,6 @@ "@kbn/core-plugins-server", "@kbn/config-schema", "@kbn/developer-examples-plugin", + "@kbn/core-feature-flags-browser", ] } diff --git a/examples/routing_example/common/index.ts b/examples/routing_example/common/index.ts index 5bec77ebe0c0..205144ad0f87 100644 --- a/examples/routing_example/common/index.ts +++ b/examples/routing_example/common/index.ts @@ -20,5 +20,8 @@ export const DEPRECATED_ROUTES = { DEPRECATED_ROUTE: '/api/routing_example/d/deprecated_route', REMOVED_ROUTE: '/api/routing_example/d/removed_route', MIGRATED_ROUTE: '/api/routing_example/d/migrated_route', - VERSIONED_ROUTE: '/api/routing_example/d/versioned', + VERSIONED_ROUTE: '/api/routing_example/d/versioned_route', + INTERNAL_DEPRECATED_ROUTE: '/api/routing_example/d/internal_deprecated_route', + INTERNAL_ONLY_ROUTE: '/internal/routing_example/d/internal_only_route', + VERSIONED_INTERNAL_ROUTE: '/internal/routing_example/d/internal_versioned_route', }; diff --git a/examples/routing_example/server/routes/deprecated_routes/index.ts b/examples/routing_example/server/routes/deprecated_routes/index.ts index 75dc0261ed1b..3fa535b171d9 100644 --- a/examples/routing_example/server/routes/deprecated_routes/index.ts +++ b/examples/routing_example/server/routes/deprecated_routes/index.ts @@ -10,8 +10,10 @@ import { IRouter } from '@kbn/core/server'; import { registerDeprecatedRoute } from './unversioned'; import { registerVersionedDeprecatedRoute } from './versioned'; +import { registerInternalDeprecatedRoute } from './internal'; export function registerDeprecatedRoutes(router: IRouter) { registerDeprecatedRoute(router); registerVersionedDeprecatedRoute(router); + registerInternalDeprecatedRoute(router); } diff --git a/examples/routing_example/server/routes/deprecated_routes/internal.ts b/examples/routing_example/server/routes/deprecated_routes/internal.ts new file mode 100644 index 000000000000..95267cb66dd3 --- /dev/null +++ b/examples/routing_example/server/routes/deprecated_routes/internal.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 { IRouter } from '@kbn/core/server'; +import { DEPRECATED_ROUTES } from '../../../common'; + +export const registerInternalDeprecatedRoute = (router: IRouter) => { + router.get( + { + path: DEPRECATED_ROUTES.INTERNAL_DEPRECATED_ROUTE, + validate: false, + options: { + // Explicitly set access is to internal + access: 'internal', + deprecated: { + documentationUrl: 'https://elastic.co/', + severity: 'critical', + message: 'Additonal message for internal deprecated api', + reason: { type: 'deprecate' }, + }, + }, + }, + async (ctx, req, res) => { + return res.ok({ + body: { + result: + 'Called deprecated route with `access: internal`. Check UA to see the deprecation.', + }, + }); + } + ); + + router.get( + { + path: DEPRECATED_ROUTES.INTERNAL_ONLY_ROUTE, + validate: false, + // If no access is specified then it defaults to internal + }, + async (ctx, req, res) => { + return res.ok({ + body: { + result: + 'Called route with `access: internal` Although this API is not marked as deprecated it will show in UA. Check UA to see the deprecation.', + }, + }); + } + ); +}; diff --git a/examples/routing_example/server/routes/deprecated_routes/versioned.ts b/examples/routing_example/server/routes/deprecated_routes/versioned.ts index 060bc64403db..6261ef6f9cb9 100644 --- a/examples/routing_example/server/routes/deprecated_routes/versioned.ts +++ b/examples/routing_example/server/routes/deprecated_routes/versioned.ts @@ -11,42 +11,72 @@ import type { IRouter } from '@kbn/core/server'; import { DEPRECATED_ROUTES } from '../../../common'; export const registerVersionedDeprecatedRoute = (router: IRouter) => { - const versionedRoute = router.versioned.get({ - path: DEPRECATED_ROUTES.VERSIONED_ROUTE, - description: 'Routing example plugin deprecated versioned route.', - access: 'internal', - options: { - excludeFromOAS: true, - }, - enableQueryVersion: true, - }); - - versionedRoute.addVersion( - { + router.versioned + .get({ + path: DEPRECATED_ROUTES.VERSIONED_ROUTE, + description: 'Routing example plugin deprecated versioned route.', + access: 'public', options: { - deprecated: { - documentationUrl: 'https://elastic.co/', - severity: 'warning', - reason: { type: 'bump', newApiVersion: '2' }, + excludeFromOAS: true, + }, + enableQueryVersion: true, + }) + .addVersion( + { + options: { + deprecated: { + documentationUrl: 'https://elastic.co/', + severity: 'warning', + reason: { type: 'deprecate' }, + }, }, + validate: false, + version: '2023-10-31', }, - validate: false, - version: '1', - }, - (ctx, req, res) => { - return res.ok({ - body: { result: 'Called deprecated version of the API. API version 1 -> 2' }, - }); - } - ); + (ctx, req, res) => { + return res.ok({ + body: { result: 'Called deprecated version of the API "2023-10-31"' }, + }); + } + ); - versionedRoute.addVersion( - { - version: '2', - validate: false, - }, - (ctx, req, res) => { - return res.ok({ body: { result: 'Called API version 2' } }); - } - ); + router.versioned + .get({ + path: DEPRECATED_ROUTES.VERSIONED_INTERNAL_ROUTE, + description: 'Routing example plugin deprecated versioned route.', + access: 'internal', + options: { + excludeFromOAS: true, + }, + enableQueryVersion: true, + }) + .addVersion( + { + options: { + deprecated: { + documentationUrl: 'https://elastic.co/', + severity: 'warning', + reason: { type: 'bump', newApiVersion: '2' }, + }, + }, + validate: false, + version: '1', + }, + (ctx, req, res) => { + return res.ok({ + body: { result: 'Called internal deprecated version of the API 1.' }, + }); + } + ) + .addVersion( + { + validate: false, + version: '2', + }, + (ctx, req, res) => { + return res.ok({ + body: { result: 'Called non-deprecated version of the API.' }, + }); + } + ); }; diff --git a/examples/routing_example/server/routes/message_routes.ts b/examples/routing_example/server/routes/message_routes.ts index c4f4aea1cf3e..ccf200e811ff 100644 --- a/examples/routing_example/server/routes/message_routes.ts +++ b/examples/routing_example/server/routes/message_routes.ts @@ -63,6 +63,9 @@ export function registerGetMessageByIdRoute(router: IRouter) { router.get( { path: `${INTERNAL_GET_MESSAGE_BY_ID_ROUTE}/{id}`, + options: { + access: 'internal', + }, validate: { params: schema.object({ id: schema.string(), diff --git a/oas_docs/README.md b/oas_docs/README.md index e37eefaed485..3312bc60771e 100644 --- a/oas_docs/README.md +++ b/oas_docs/README.md @@ -45,8 +45,7 @@ Besides the scripts in the `oas_docs/scripts` folder, there is an `oas_docs/make | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `api-docs` | Builds ESS Kibana OpenAPI bundle | | `api-docs-serverless` | Builds Serverless Kibana OpenAPI bundle | -| `api-docs-lint` | Lints built result bundles | -| `api-docs-lint-errs` | Lints built result bundles for errors | +| `api-docs-lint` | Lints built result bundles | | `api-docs-preview` | Generates (ESS + Serverless) Kibana OpenAPI bundles preview | | `api-docs-overlay` | Applies [overlays](https://docs.bump.sh/help/specification-support/overlays/) from `overlays` folder to the Kibana OpenAPI bundles and generate `*.new.yaml` files. Overlays help to fine tune the result bundles. | | `api-docs-overlay-preview` | Generates a preview for bundles produced by `api-docs-overlay` | diff --git a/oas_docs/bundle.json b/oas_docs/bundle.json index 19094b82be09..aa53ce68e54f 100644 --- a/oas_docs/bundle.json +++ b/oas_docs/bundle.json @@ -5628,7 +5628,6 @@ }, "/api/fleet/agent_download_sources": { "get": { - "description": "List agent binary download sources", "operationId": "get-fleet-agent-download-sources", "parameters": [ { @@ -5731,13 +5730,12 @@ } } }, - "summary": "", + "summary": "Get agent binary download sources", "tags": [ "Elastic Agent binary download sources" ] }, "post": { - "description": "Create agent binary download source", "operationId": "post-fleet-agent-download-sources", "parameters": [ { @@ -5870,7 +5868,7 @@ } } }, - "summary": "", + "summary": "Create an agent binary download source", "tags": [ "Elastic Agent binary download sources" ] @@ -5878,7 +5876,7 @@ }, "/api/fleet/agent_download_sources/{sourceId}": { "delete": { - "description": "Delete agent binary download source by ID", + "description": "Delete an agent binary download source by ID.", "operationId": "delete-fleet-agent-download-sources-sourceid", "parameters": [ { @@ -5957,13 +5955,13 @@ } } }, - "summary": "", + "summary": "Delete an agent binary download source", "tags": [ "Elastic Agent binary download sources" ] }, "get": { - "description": "Get agent binary download source by ID", + "description": "Get an agent binary download source by ID.", "operationId": "get-fleet-agent-download-sources-sourceid", "parameters": [ { @@ -6059,13 +6057,13 @@ } } }, - "summary": "", + "summary": "Get an agent binary download source", "tags": [ "Elastic Agent binary download sources" ] }, "put": { - "description": "Update agent binary download source by ID", + "description": "Update an agent binary download source by ID.", "operationId": "put-fleet-agent-download-sources-sourceid", "parameters": [ { @@ -6206,7 +6204,7 @@ } } }, - "summary": "", + "summary": "Update an agent binary download source", "tags": [ "Elastic Agent binary download sources" ] @@ -6214,7 +6212,6 @@ }, "/api/fleet/agent_policies": { "get": { - "description": "List agent policies", "operationId": "get-fleet-agent-policies", "parameters": [ { @@ -7046,13 +7043,12 @@ } } }, - "summary": "", + "summary": "Get agent policies", "tags": [ "Elastic Agent policies" ] }, "post": { - "description": "Create an agent policy", "operationId": "post-fleet-agent-policies", "parameters": [ { @@ -8039,7 +8035,7 @@ } } }, - "summary": "", + "summary": "Create an agent policy", "tags": [ "Elastic Agent policies" ] @@ -8047,7 +8043,6 @@ }, "/api/fleet/agent_policies/_bulk_get": { "post": { - "description": "Bulk get agent policies", "operationId": "post-fleet-agent-policies-bulk-get", "parameters": [ { @@ -8826,7 +8821,7 @@ } } }, - "summary": "", + "summary": "Bulk get agent policies", "tags": [ "Elastic Agent policies" ] @@ -8834,7 +8829,7 @@ }, "/api/fleet/agent_policies/delete": { "post": { - "description": "Delete agent policy by ID", + "description": "Delete an agent policy by ID.", "operationId": "post-fleet-agent-policies-delete", "parameters": [ { @@ -8931,7 +8926,7 @@ } } }, - "summary": "", + "summary": "Delete an agent policy", "tags": [ "Elastic Agent policies" ] @@ -8939,7 +8934,7 @@ }, "/api/fleet/agent_policies/outputs": { "post": { - "description": "Get list of outputs associated with agent policies", + "description": "Get a list of outputs associated with agent policies.", "operationId": "post-fleet-agent-policies-outputs", "parameters": [ { @@ -9116,7 +9111,7 @@ } } }, - "summary": "", + "summary": "Get outputs for agent policies", "tags": [ "Elastic Agent policies" ] @@ -9124,7 +9119,7 @@ }, "/api/fleet/agent_policies/{agentPolicyId}": { "get": { - "description": "Get an agent policy by ID", + "description": "Get an agent policy by ID.", "operationId": "get-fleet-agent-policies-agentpolicyid", "parameters": [ { @@ -9869,13 +9864,13 @@ } } }, - "summary": "", + "summary": "Get an agent policy", "tags": [ "Elastic Agent policies" ] }, "put": { - "description": "Update an agent policy by ID", + "description": "Update an agent policy by ID.", "operationId": "put-fleet-agent-policies-agentpolicyid", "parameters": [ { @@ -10874,7 +10869,7 @@ } } }, - "summary": "", + "summary": "Update an agent policy", "tags": [ "Elastic Agent policies" ] @@ -10882,7 +10877,7 @@ }, "/api/fleet/agent_policies/{agentPolicyId}/copy": { "post": { - "description": "Copy an agent policy by ID", + "description": "Copy an agent policy by ID.", "operationId": "post-fleet-agent-policies-agentpolicyid-copy", "parameters": [ { @@ -11659,7 +11654,7 @@ } } }, - "summary": "", + "summary": "Copy an agent policy", "tags": [ "Elastic Agent policies" ] @@ -11667,7 +11662,7 @@ }, "/api/fleet/agent_policies/{agentPolicyId}/download": { "get": { - "description": "Download an agent policy by ID", + "description": "Download an agent policy by ID.", "operationId": "get-fleet-agent-policies-agentpolicyid-download", "parameters": [ { @@ -11776,7 +11771,7 @@ } } }, - "summary": "", + "summary": "Download an agent policy", "tags": [ "Elastic Agent policies" ] @@ -11784,7 +11779,7 @@ }, "/api/fleet/agent_policies/{agentPolicyId}/full": { "get": { - "description": "Get a full agent policy by ID", + "description": "Get a full agent policy by ID.", "operationId": "get-fleet-agent-policies-agentpolicyid-full", "parameters": [ { @@ -12278,7 +12273,7 @@ } } }, - "summary": "", + "summary": "Get a full agent policy", "tags": [ "Elastic Agent policies" ] @@ -12286,7 +12281,7 @@ }, "/api/fleet/agent_policies/{agentPolicyId}/outputs": { "get": { - "description": "Get list of outputs associated with agent policy by policy id", + "description": "Get a list of outputs associated with agent policy by policy id.", "operationId": "get-fleet-agent-policies-agentpolicyid-outputs", "parameters": [ { @@ -12436,7 +12431,7 @@ } } }, - "summary": "", + "summary": "Get outputs for an agent policy", "tags": [ "Elastic Agent policies" ] @@ -12444,7 +12439,6 @@ }, "/api/fleet/agent_status": { "get": { - "description": "Get agent status summary", "operationId": "get-fleet-agent-status", "parameters": [ { @@ -12584,7 +12578,7 @@ } } }, - "summary": "", + "summary": "Get an agent status summary", "tags": [ "Elastic Agent status" ] @@ -12592,7 +12586,6 @@ }, "/api/fleet/agent_status/data": { "get": { - "description": "Get incoming agent data", "operationId": "get-fleet-agent-status-data", "parameters": [ { @@ -12700,7 +12693,7 @@ } } }, - "summary": "", + "summary": "Get incoming agent data", "tags": [ "Elastic Agents" ] @@ -12708,7 +12701,6 @@ }, "/api/fleet/agents": { "get": { - "description": "List agents", "operationId": "get-fleet-agents", "parameters": [ { @@ -13253,13 +13245,12 @@ } } }, - "summary": "", + "summary": "Get agents", "tags": [ "Elastic Agents" ] }, "post": { - "description": "List agents by action ids", "operationId": "post-fleet-agents", "parameters": [ { @@ -13354,7 +13345,7 @@ } } }, - "summary": "", + "summary": "Get agents by action ids", "tags": [ "Elastic Agents" ] @@ -13362,7 +13353,6 @@ }, "/api/fleet/agents/action_status": { "get": { - "description": "Get agent action status", "operationId": "get-fleet-agents-action-status", "parameters": [ { @@ -13590,7 +13580,7 @@ } } }, - "summary": "", + "summary": "Get an agent action status", "tags": [ "Elastic Agent actions" ] @@ -13598,7 +13588,6 @@ }, "/api/fleet/agents/actions/{actionId}/cancel": { "post": { - "description": "Cancel agent action", "operationId": "post-fleet-agents-actions-actionid-cancel", "parameters": [ { @@ -13732,7 +13721,7 @@ } } }, - "summary": "", + "summary": "Cancel an agent action", "tags": [ "Elastic Agent actions" ] @@ -13740,7 +13729,6 @@ }, "/api/fleet/agents/available_versions": { "get": { - "description": "Get available agent versions", "operationId": "get-fleet-agents-available-versions", "parameters": [ { @@ -13804,7 +13792,7 @@ } } }, - "summary": "", + "summary": "Get available agent versions", "tags": [ "Elastic Agents" ] @@ -13812,7 +13800,6 @@ }, "/api/fleet/agents/bulk_reassign": { "post": { - "description": "Bulk reassign agents", "operationId": "post-fleet-agents-bulk-reassign", "parameters": [ { @@ -13922,7 +13909,7 @@ } } }, - "summary": "", + "summary": "Bulk reassign agents", "tags": [ "Elastic Agent actions" ] @@ -13930,7 +13917,6 @@ }, "/api/fleet/agents/bulk_request_diagnostics": { "post": { - "description": "Bulk request diagnostics from agents", "operationId": "post-fleet-agents-bulk-request-diagnostics", "parameters": [ { @@ -14041,7 +14027,7 @@ } } }, - "summary": "", + "summary": "Bulk request diagnostics from agents", "tags": [ "Elastic Agent actions" ] @@ -14049,7 +14035,6 @@ }, "/api/fleet/agents/bulk_unenroll": { "post": { - "description": "Bulk unenroll agents", "operationId": "post-fleet-agents-bulk-unenroll", "parameters": [ { @@ -14165,7 +14150,7 @@ } } }, - "summary": "", + "summary": "Bulk unenroll agents", "tags": [ "Elastic Agent actions" ] @@ -14173,7 +14158,6 @@ }, "/api/fleet/agents/bulk_update_agent_tags": { "post": { - "description": "Bulk update agent tags", "operationId": "post-fleet-agents-bulk-update-agent-tags", "parameters": [ { @@ -14291,7 +14275,7 @@ } } }, - "summary": "", + "summary": "Bulk update agent tags", "tags": [ "Elastic Agent actions" ] @@ -14299,7 +14283,6 @@ }, "/api/fleet/agents/bulk_upgrade": { "post": { - "description": "Bulk upgrade agents", "operationId": "post-fleet-agents-bulk-upgrade", "parameters": [ { @@ -14425,7 +14408,7 @@ } } }, - "summary": "", + "summary": "Bulk upgrade agents", "tags": [ "Elastic Agent actions" ] @@ -14433,7 +14416,7 @@ }, "/api/fleet/agents/files/{fileId}": { "delete": { - "description": "Delete file uploaded by agent", + "description": "Delete a file uploaded by an agent.", "operationId": "delete-fleet-agents-files-fileid", "parameters": [ { @@ -14516,7 +14499,7 @@ } } }, - "summary": "", + "summary": "Delete an uploaded file", "tags": [ "Elastic Agents" ] @@ -14524,7 +14507,7 @@ }, "/api/fleet/agents/files/{fileId}/{fileName}": { "get": { - "description": "Get file uploaded by agent", + "description": "Get a file uploaded by an agent.", "operationId": "get-fleet-agents-files-fileid-filename", "parameters": [ { @@ -14592,7 +14575,7 @@ } } }, - "summary": "", + "summary": "Get an uploaded file", "tags": [ "Elastic Agents" ] @@ -14600,7 +14583,6 @@ }, "/api/fleet/agents/setup": { "get": { - "description": "Get agent setup info", "operationId": "get-fleet-agents-setup", "parameters": [ { @@ -14695,13 +14677,12 @@ } } }, - "summary": "", + "summary": "Get agent setup info", "tags": [ "Elastic Agents" ] }, "post": { - "description": "Initiate agent setup", "operationId": "post-fleet-agents-setup", "parameters": [ { @@ -14793,7 +14774,7 @@ } } }, - "summary": "", + "summary": "Initiate agent setup", "tags": [ "Elastic Agents" ] @@ -14801,7 +14782,6 @@ }, "/api/fleet/agents/tags": { "get": { - "description": "List agent tags", "operationId": "get-fleet-agents-tags", "parameters": [ { @@ -14882,7 +14862,7 @@ } } }, - "summary": "", + "summary": "Get agent tags", "tags": [ "Elastic Agents" ] @@ -14890,7 +14870,7 @@ }, "/api/fleet/agents/{agentId}": { "delete": { - "description": "Delete agent by ID", + "description": "Delete an agent by ID.", "operationId": "delete-fleet-agents-agentid", "parameters": [ { @@ -14972,13 +14952,13 @@ } } }, - "summary": "", + "summary": "Delete an agent", "tags": [ "Elastic Agents" ] }, "get": { - "description": "Get agent by ID", + "description": "Get an agent by ID.", "operationId": "get-fleet-agents-agentid", "parameters": [ { @@ -15437,13 +15417,13 @@ } } }, - "summary": "", + "summary": "Get an agent", "tags": [ "Elastic Agents" ] }, "put": { - "description": "Update agent by ID", + "description": "Update an agent by ID.", "operationId": "put-fleet-agents-agentid", "parameters": [ { @@ -15925,7 +15905,7 @@ } } }, - "summary": "", + "summary": "Update an agent", "tags": [ "Elastic Agents" ] @@ -15933,7 +15913,6 @@ }, "/api/fleet/agents/{agentId}/actions": { "post": { - "description": "Create agent action", "operationId": "post-fleet-agents-agentid-actions", "parameters": [ { @@ -16142,7 +16121,7 @@ } } }, - "summary": "", + "summary": "Create an agent action", "tags": [ "Elastic Agent actions" ] @@ -16150,7 +16129,6 @@ }, "/api/fleet/agents/{agentId}/reassign": { "post": { - "description": "Reassign agent", "operationId": "post-fleet-agents-agentid-reassign", "parameters": [ { @@ -16240,7 +16218,7 @@ } } }, - "summary": "", + "summary": "Reassign an agent", "tags": [ "Elastic Agent actions" ] @@ -16248,7 +16226,6 @@ }, "/api/fleet/agents/{agentId}/request_diagnostics": { "post": { - "description": "Request agent diagnostics", "operationId": "post-fleet-agents-agentid-request-diagnostics", "parameters": [ { @@ -16349,7 +16326,7 @@ } } }, - "summary": "", + "summary": "Request agent diagnostics", "tags": [ "Elastic Agent actions" ] @@ -16357,7 +16334,6 @@ }, "/api/fleet/agents/{agentId}/unenroll": { "post": { - "description": "Unenroll agent", "operationId": "post-fleet-agents-agentid-unenroll", "parameters": [ { @@ -16411,7 +16387,7 @@ } }, "responses": {}, - "summary": "", + "summary": "Unenroll an agent", "tags": [ "Elastic Agent actions" ] @@ -16419,7 +16395,6 @@ }, "/api/fleet/agents/{agentId}/upgrade": { "post": { - "description": "Upgrade agent", "operationId": "post-fleet-agents-agentid-upgrade", "parameters": [ { @@ -16518,7 +16493,7 @@ } } }, - "summary": "", + "summary": "Upgrade an agent", "tags": [ "Elastic Agent actions" ] @@ -16526,7 +16501,6 @@ }, "/api/fleet/agents/{agentId}/uploads": { "get": { - "description": "List agent uploads", "operationId": "get-fleet-agents-agentid-uploads", "parameters": [ { @@ -16638,7 +16612,7 @@ } } }, - "summary": "", + "summary": "Get agent uploads", "tags": [ "Elastic Agents" ] @@ -16646,7 +16620,6 @@ }, "/api/fleet/check-permissions": { "get": { - "description": "Check permissions", "operationId": "get-fleet-check-permissions", "parameters": [ { @@ -16723,7 +16696,7 @@ } } }, - "summary": "", + "summary": "Check permissions", "tags": [ "Fleet internals" ] @@ -16731,7 +16704,6 @@ }, "/api/fleet/data_streams": { "get": { - "description": "List data streams", "operationId": "get-fleet-data-streams", "parameters": [ { @@ -16881,7 +16853,7 @@ } } }, - "summary": "", + "summary": "Get data streams", "tags": [ "Data streams" ] @@ -16889,7 +16861,6 @@ }, "/api/fleet/enrollment_api_keys": { "get": { - "description": "List enrollment API keys", "operationId": "get-fleet-enrollment-api-keys", "parameters": [ { @@ -17027,13 +16998,12 @@ } } }, - "summary": "", + "summary": "Get enrollment API keys", "tags": [ "Fleet enrollment API keys" ] }, "post": { - "description": "Create enrollment API key", "operationId": "post-fleet-enrollment-api-keys", "parameters": [ { @@ -17171,7 +17141,7 @@ } } }, - "summary": "", + "summary": "Create an enrollment API key", "tags": [ "Fleet enrollment API keys" ] @@ -17179,7 +17149,7 @@ }, "/api/fleet/enrollment_api_keys/{keyId}": { "delete": { - "description": "Revoke enrollment API key by ID by marking it as inactive", + "description": "Revoke an enrollment API key by ID by marking it as inactive.", "operationId": "delete-fleet-enrollment-api-keys-keyid", "parameters": [ { @@ -17261,13 +17231,13 @@ } } }, - "summary": "", + "summary": "Revoke an enrollment API key", "tags": [ "Fleet enrollment API keys" ] }, "get": { - "description": "Get enrollment API key by ID", + "description": "Get an enrollment API key by ID.", "operationId": "get-fleet-enrollment-api-keys-keyid", "parameters": [ { @@ -17372,7 +17342,7 @@ } } }, - "summary": "", + "summary": "Get an enrollment API key", "tags": [ "Fleet enrollment API keys" ] @@ -17380,7 +17350,6 @@ }, "/api/fleet/epm/bulk_assets": { "post": { - "description": "Bulk get assets", "operationId": "post-fleet-epm-bulk-assets", "parameters": [ { @@ -17523,7 +17492,7 @@ } } }, - "summary": "", + "summary": "Bulk get assets", "tags": [ "Elastic Package Manager (EPM)" ] @@ -17531,7 +17500,6 @@ }, "/api/fleet/epm/categories": { "get": { - "description": "List package categories", "operationId": "get-fleet-epm-categories", "parameters": [ { @@ -17634,7 +17602,7 @@ } } }, - "summary": "", + "summary": "Get package categories", "tags": [ "Elastic Package Manager (EPM)" ] @@ -17642,7 +17610,6 @@ }, "/api/fleet/epm/custom_integrations": { "post": { - "description": "Create custom integration", "operationId": "post-fleet-epm-custom-integrations", "parameters": [ { @@ -17843,7 +17810,7 @@ } } }, - "summary": "", + "summary": "Create a custom integration", "tags": [ "Elastic Package Manager (EPM)" ] @@ -17851,7 +17818,6 @@ }, "/api/fleet/epm/data_streams": { "get": { - "description": "List data streams", "operationId": "get-fleet-epm-data-streams", "parameters": [ { @@ -17969,7 +17935,7 @@ } } }, - "summary": "", + "summary": "Get data streams", "tags": [ "Data streams" ] @@ -17977,7 +17943,6 @@ }, "/api/fleet/epm/packages": { "get": { - "description": "List packages", "operationId": "get-fleet-epm-packages", "parameters": [ { @@ -18543,13 +18508,12 @@ } } }, - "summary": "", + "summary": "Get packages", "tags": [ "Elastic Package Manager (EPM)" ] }, "post": { - "description": "Install package by upload", "operationId": "post-fleet-epm-packages", "parameters": [ { @@ -18730,7 +18694,7 @@ } } }, - "summary": "", + "summary": "Install a package by upload", "tags": [ "Elastic Package Manager (EPM)" ] @@ -18738,7 +18702,6 @@ }, "/api/fleet/epm/packages/_bulk": { "post": { - "description": "Bulk install packages", "operationId": "post-fleet-epm-packages-bulk", "parameters": [ { @@ -19008,7 +18971,7 @@ } } }, - "summary": "", + "summary": "Bulk install packages", "tags": [ "Elastic Package Manager (EPM)" ] @@ -19016,7 +18979,6 @@ }, "/api/fleet/epm/packages/installed": { "get": { - "description": "Get installed packages", "operationId": "get-fleet-epm-packages-installed", "parameters": [ { @@ -19249,7 +19211,7 @@ } } }, - "summary": "", + "summary": "Get installed packages", "tags": [ "Elastic Package Manager (EPM)" ] @@ -19257,7 +19219,6 @@ }, "/api/fleet/epm/packages/limited": { "get": { - "description": "Get limited package list", "operationId": "get-fleet-epm-packages-limited", "parameters": [ { @@ -19321,7 +19282,7 @@ } } }, - "summary": "", + "summary": "Get a limited package list", "tags": [ "Elastic Package Manager (EPM)" ] @@ -19329,7 +19290,6 @@ }, "/api/fleet/epm/packages/{pkgName}/stats": { "get": { - "description": "Get package stats", "operationId": "get-fleet-epm-packages-pkgname-stats", "parameters": [ { @@ -19407,7 +19367,7 @@ } } }, - "summary": "", + "summary": "Get package stats", "tags": [ "Elastic Package Manager (EPM)" ] @@ -19415,7 +19375,6 @@ }, "/api/fleet/epm/packages/{pkgName}/{pkgVersion}": { "delete": { - "description": "Delete package", "operationId": "delete-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { @@ -19579,13 +19538,12 @@ } } }, - "summary": "", + "summary": "Delete a package", "tags": [ "Elastic Package Manager (EPM)" ] }, "get": { - "description": "Get package", "operationId": "get-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { @@ -20271,13 +20229,12 @@ } } }, - "summary": "", + "summary": "Get a package", "tags": [ "Elastic Package Manager (EPM)" ] }, "post": { - "description": "Install package from registry", "operationId": "post-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { @@ -20493,13 +20450,12 @@ } } }, - "summary": "", + "summary": "Install a package from the registry", "tags": [ "Elastic Package Manager (EPM)" ] }, "put": { - "description": "Update package settings", "operationId": "put-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { @@ -21168,7 +21124,7 @@ } } }, - "summary": "", + "summary": "Update package settings", "tags": [ "Elastic Package Manager (EPM)" ] @@ -21176,7 +21132,6 @@ }, "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/transforms/authorize": { "post": { - "description": "Authorize transforms", "operationId": "post-fleet-epm-packages-pkgname-pkgversion-transforms-authorize", "parameters": [ { @@ -21312,7 +21267,7 @@ } } }, - "summary": "", + "summary": "Authorize transforms", "tags": [ "Elastic Package Manager (EPM)" ] @@ -21320,7 +21275,6 @@ }, "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/{filePath*}": { "get": { - "description": "Get package file", "operationId": "get-fleet-epm-packages-pkgname-pkgversion-filepath", "parameters": [ { @@ -21394,7 +21348,7 @@ } } }, - "summary": "", + "summary": "Get a package file", "tags": [ "Elastic Package Manager (EPM)" ] @@ -21402,7 +21356,6 @@ }, "/api/fleet/epm/templates/{pkgName}/{pkgVersion}/inputs": { "get": { - "description": "Get inputs template", "operationId": "get-fleet-epm-templates-pkgname-pkgversion-inputs", "parameters": [ { @@ -21563,7 +21516,7 @@ } } }, - "summary": "", + "summary": "Get an inputs template", "tags": [ "Elastic Package Manager (EPM)" ] @@ -21571,7 +21524,6 @@ }, "/api/fleet/epm/verification_key_id": { "get": { - "description": "Get a package signature verification key ID", "operationId": "get-fleet-epm-verification-key-id", "parameters": [ { @@ -21633,7 +21585,7 @@ } } }, - "summary": "", + "summary": "Get a package signature verification key ID", "tags": [ "Elastic Package Manager (EPM)" ] @@ -21641,7 +21593,6 @@ }, "/api/fleet/fleet_server_hosts": { "get": { - "description": "List Fleet Server hosts", "operationId": "get-fleet-fleet-server-hosts", "parameters": [ { @@ -21753,13 +21704,12 @@ } } }, - "summary": "", + "summary": "Get Fleet Server hosts", "tags": [ "Fleet Server hosts" ] }, "post": { - "description": "Create Fleet Server host", "operationId": "post-fleet-fleet-server-hosts", "parameters": [ { @@ -21910,7 +21860,7 @@ } } }, - "summary": "", + "summary": "Create a Fleet Server host", "tags": [ "Fleet Server hosts" ] @@ -21918,7 +21868,7 @@ }, "/api/fleet/fleet_server_hosts/{itemId}": { "delete": { - "description": "Delete Fleet Server host by ID", + "description": "Delete a Fleet Server host by ID.", "operationId": "delete-fleet-fleet-server-hosts-itemid", "parameters": [ { @@ -21997,13 +21947,13 @@ } } }, - "summary": "", + "summary": "Delete a Fleet Server host", "tags": [ "Fleet Server hosts" ] }, "get": { - "description": "Get Fleet Server host by ID", + "description": "Get a Fleet Server host by ID.", "operationId": "get-fleet-fleet-server-hosts-itemid", "parameters": [ { @@ -22108,13 +22058,13 @@ } } }, - "summary": "", + "summary": "Get a Fleet Server host", "tags": [ "Fleet Server hosts" ] }, "put": { - "description": "Update Fleet Server host by ID", + "description": "Update a Fleet Server host by ID.", "operationId": "put-fleet-fleet-server-hosts-itemid", "parameters": [ { @@ -22264,7 +22214,7 @@ } } }, - "summary": "", + "summary": "Update a Fleet Server host", "tags": [ "Fleet Server hosts" ] @@ -22272,7 +22222,6 @@ }, "/api/fleet/health_check": { "post": { - "description": "Check Fleet Server health", "operationId": "post-fleet-health-check", "parameters": [ { @@ -22392,7 +22341,7 @@ } } }, - "summary": "", + "summary": "Check Fleet Server health", "tags": [ "Fleet internals" ] @@ -22400,7 +22349,6 @@ }, "/api/fleet/kubernetes": { "get": { - "description": "Get full K8s agent manifest", "operationId": "get-fleet-kubernetes", "parameters": [ { @@ -22485,7 +22433,7 @@ } } }, - "summary": "", + "summary": "Get a full K8s agent manifest", "tags": [ "Elastic Agent policies" ] @@ -22593,7 +22541,7 @@ } } }, - "summary": "", + "summary": "Download an agent manifest", "tags": [ "Elastic Agent policies" ] @@ -22601,7 +22549,6 @@ }, "/api/fleet/logstash_api_keys": { "post": { - "description": "Generate Logstash API key", "operationId": "post-fleet-logstash-api-keys", "parameters": [ { @@ -22672,7 +22619,7 @@ } } }, - "summary": "", + "summary": "Generate a Logstash API key", "tags": [ "Fleet outputs" ] @@ -22680,7 +22627,6 @@ }, "/api/fleet/message_signing_service/rotate_key_pair": { "post": { - "description": "Rotate fleet message signing key pair", "operationId": "post-fleet-message-signing-service-rotate-key-pair", "parameters": [ { @@ -22785,7 +22731,7 @@ } } }, - "summary": "", + "summary": "Rotate a Fleet message signing key pair", "tags": [ "Message Signing Service" ] @@ -22793,7 +22739,6 @@ }, "/api/fleet/outputs": { "get": { - "description": "List outputs", "operationId": "get-fleet-outputs", "parameters": [ { @@ -23782,39 +23727,6 @@ "topic": { "type": "string" }, - "topics": { - "items": { - "additionalProperties": true, - "properties": { - "topic": { - "type": "string" - }, - "when": { - "additionalProperties": true, - "properties": { - "condition": { - "type": "string" - }, - "type": { - "enum": [ - "equals", - "contains", - "regexp" - ], - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "topic" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, "type": { "enum": [ "kafka" @@ -23917,13 +23829,12 @@ } } }, - "summary": "", + "summary": "Get outputs", "tags": [ "Fleet outputs" ] }, "post": { - "description": "Create output", "operationId": "post-fleet-outputs", "parameters": [ { @@ -24917,39 +24828,6 @@ "topic": { "type": "string" }, - "topics": { - "items": { - "additionalProperties": false, - "properties": { - "topic": { - "type": "string" - }, - "when": { - "additionalProperties": false, - "properties": { - "condition": { - "type": "string" - }, - "type": { - "enum": [ - "equals", - "contains", - "regexp" - ], - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "topic" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, "type": { "enum": [ "kafka" @@ -25978,39 +25856,6 @@ "topic": { "type": "string" }, - "topics": { - "items": { - "additionalProperties": true, - "properties": { - "topic": { - "type": "string" - }, - "when": { - "additionalProperties": true, - "properties": { - "condition": { - "type": "string" - }, - "type": { - "enum": [ - "equals", - "contains", - "regexp" - ], - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "topic" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, "type": { "enum": [ "kafka" @@ -26099,7 +25944,7 @@ } } }, - "summary": "", + "summary": "Create output", "tags": [ "Fleet outputs" ] @@ -26107,7 +25952,7 @@ }, "/api/fleet/outputs/{outputId}": { "delete": { - "description": "Delete output by ID", + "description": "Delete output by ID.", "operationId": "delete-fleet-outputs-outputid", "parameters": [ { @@ -26211,13 +26056,13 @@ } } }, - "summary": "", + "summary": "Delete output", "tags": [ "Fleet outputs" ] }, "get": { - "description": "Get output by ID", + "description": "Get output by ID.", "operationId": "get-fleet-outputs-outputid", "parameters": [ { @@ -27213,39 +27058,6 @@ "topic": { "type": "string" }, - "topics": { - "items": { - "additionalProperties": true, - "properties": { - "topic": { - "type": "string" - }, - "when": { - "additionalProperties": true, - "properties": { - "condition": { - "type": "string" - }, - "type": { - "enum": [ - "equals", - "contains", - "regexp" - ], - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "topic" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, "type": { "enum": [ "kafka" @@ -27334,13 +27146,13 @@ } } }, - "summary": "", + "summary": "Get output", "tags": [ "Fleet outputs" ] }, "put": { - "description": "Update output by ID", + "description": "Update output by ID.", "operationId": "put-fleet-outputs-outputid", "parameters": [ { @@ -28321,39 +28133,6 @@ "topic": { "type": "string" }, - "topics": { - "items": { - "additionalProperties": false, - "properties": { - "topic": { - "type": "string" - }, - "when": { - "additionalProperties": false, - "properties": { - "condition": { - "type": "string" - }, - "type": { - "enum": [ - "equals", - "contains", - "regexp" - ], - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "topic" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, "type": { "enum": [ "kafka" @@ -29379,39 +29158,6 @@ "topic": { "type": "string" }, - "topics": { - "items": { - "additionalProperties": true, - "properties": { - "topic": { - "type": "string" - }, - "when": { - "additionalProperties": true, - "properties": { - "condition": { - "type": "string" - }, - "type": { - "enum": [ - "equals", - "contains", - "regexp" - ], - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "topic" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, "type": { "enum": [ "kafka" @@ -29500,7 +29246,7 @@ } } }, - "summary": "", + "summary": "Update output", "tags": [ "Fleet outputs" ] @@ -29508,7 +29254,6 @@ }, "/api/fleet/outputs/{outputId}/health": { "get": { - "description": "Get latest output health", "operationId": "get-fleet-outputs-outputid-health", "parameters": [ { @@ -29588,7 +29333,7 @@ } } }, - "summary": "", + "summary": "Get the latest output health", "tags": [ "Fleet outputs" ] @@ -29596,7 +29341,6 @@ }, "/api/fleet/package_policies": { "get": { - "description": "List package policies", "operationId": "get-fleet-package-policies", "parameters": [ { @@ -30305,13 +30049,12 @@ } } }, - "summary": "", + "summary": "Get package policies", "tags": [ "Fleet package policies" ] }, "post": { - "description": "Create package policy", "operationId": "post-fleet-package-policies", "parameters": [ { @@ -31577,7 +31320,7 @@ } } }, - "summary": "", + "summary": "Create a package policy", "tags": [ "Fleet package policies" ] @@ -31585,7 +31328,6 @@ }, "/api/fleet/package_policies/_bulk_get": { "post": { - "description": "Bulk get package policies", "operationId": "post-fleet-package-policies-bulk-get", "parameters": [ { @@ -32275,7 +32017,7 @@ } } }, - "summary": "", + "summary": "Bulk get package policies", "tags": [ "Fleet package policies" ] @@ -32283,7 +32025,6 @@ }, "/api/fleet/package_policies/delete": { "post": { - "description": "Bulk delete package policies", "operationId": "post-fleet-package-policies-delete", "parameters": [ { @@ -32479,7 +32220,7 @@ } } }, - "summary": "", + "summary": "Bulk delete package policies", "tags": [ "Fleet package policies" ] @@ -32487,7 +32228,7 @@ }, "/api/fleet/package_policies/upgrade": { "post": { - "description": "Upgrade package policy to a newer package version", + "description": "Upgrade a package policy to a newer package version.", "operationId": "post-fleet-package-policies-upgrade", "parameters": [ { @@ -32604,7 +32345,7 @@ } } }, - "summary": "", + "summary": "Upgrade a package policy", "tags": [ "Fleet package policies" ] @@ -32612,7 +32353,6 @@ }, "/api/fleet/package_policies/upgrade/dryrun": { "post": { - "description": "Dry run package policy upgrade", "operationId": "post-fleet-package-policies-upgrade-dryrun", "parameters": [ { @@ -33790,7 +33530,7 @@ } } }, - "summary": "", + "summary": "Dry run a package policy upgrade", "tags": [ "Fleet package policies" ] @@ -33798,7 +33538,7 @@ }, "/api/fleet/package_policies/{packagePolicyId}": { "delete": { - "description": "Delete package policy by ID", + "description": "Delete a package policy by ID.", "operationId": "delete-fleet-package-policies-packagepolicyid", "parameters": [ { @@ -33885,13 +33625,13 @@ } } }, - "summary": "", + "summary": "Delete a package policy", "tags": [ "Fleet package policies" ] }, "get": { - "description": "Get package policy by ID", + "description": "Get a package policy by ID.", "operationId": "get-fleet-package-policies-packagepolicyid", "parameters": [ { @@ -34551,13 +34291,13 @@ } } }, - "summary": "", + "summary": "Get a package policy", "tags": [ "Fleet package policies" ] }, "put": { - "description": "Update package policy by ID", + "description": "Update a package policy by ID.", "operationId": "put-fleet-package-policies-packagepolicyid", "parameters": [ { @@ -35823,7 +35563,7 @@ } } }, - "summary": "", + "summary": "Update a package policy", "tags": [ "Fleet package policies" ] @@ -35831,7 +35571,6 @@ }, "/api/fleet/proxies": { "get": { - "description": "List proxies", "operationId": "get-fleet-proxies", "parameters": [ { @@ -35957,13 +35696,12 @@ } } }, - "summary": "", + "summary": "Get proxies", "tags": [ "Fleet proxies" ] }, "post": { - "description": "Create proxy", "operationId": "post-fleet-proxies", "parameters": [ { @@ -36142,7 +35880,7 @@ } } }, - "summary": "", + "summary": "Create a proxy", "tags": [ "Fleet proxies" ] @@ -36150,7 +35888,7 @@ }, "/api/fleet/proxies/{itemId}": { "delete": { - "description": "Delete proxy by ID", + "description": "Delete a proxy by ID", "operationId": "delete-fleet-proxies-itemid", "parameters": [ { @@ -36229,13 +35967,13 @@ } } }, - "summary": "", + "summary": "Delete a proxy", "tags": [ "Fleet proxies" ] }, "get": { - "description": "Get proxy by ID", + "description": "Get a proxy by ID.", "operationId": "get-fleet-proxies-itemid", "parameters": [ { @@ -36354,13 +36092,13 @@ } } }, - "summary": "", + "summary": "Get a proxy", "tags": [ "Fleet proxies" ] }, "put": { - "description": "Update proxy by ID", + "description": "Update a proxy by ID.", "operationId": "put-fleet-proxies-itemid", "parameters": [ { @@ -36542,7 +36280,7 @@ } } }, - "summary": "", + "summary": "Update a proxy", "tags": [ "Fleet proxies" ] @@ -36550,7 +36288,6 @@ }, "/api/fleet/service_tokens": { "post": { - "description": "Create a service token", "operationId": "post-fleet-service-tokens", "parameters": [ { @@ -36642,7 +36379,7 @@ } } }, - "summary": "", + "summary": "Create a service token", "tags": [ "Fleet service tokens" ] @@ -36650,7 +36387,6 @@ }, "/api/fleet/settings": { "get": { - "description": "Get settings", "operationId": "get-fleet-settings", "parameters": [ { @@ -36789,13 +36525,12 @@ } } }, - "summary": "", + "summary": "Get settings", "tags": [ "Fleet internals" ] }, "put": { - "description": "Update settings", "operationId": "put-fleet-settings", "parameters": [ { @@ -36991,7 +36726,7 @@ } } }, - "summary": "", + "summary": "Update settings", "tags": [ "Fleet internals" ] @@ -36999,7 +36734,6 @@ }, "/api/fleet/setup": { "post": { - "description": "Initiate Fleet setup", "operationId": "post-fleet-setup", "parameters": [ { @@ -37110,7 +36844,7 @@ } } }, - "summary": "", + "summary": "Initiate Fleet setup", "tags": [ "Fleet internals" ] @@ -37118,7 +36852,7 @@ }, "/api/fleet/uninstall_tokens": { "get": { - "description": "List metadata for latest uninstall tokens per agent policy", + "description": "List the metadata for the latest uninstall tokens per agent policy.", "operationId": "get-fleet-uninstall-tokens", "parameters": [ { @@ -37259,7 +36993,7 @@ } } }, - "summary": "", + "summary": "Get metadata for latest uninstall tokens", "tags": [ "Fleet uninstall tokens" ] @@ -37267,7 +37001,7 @@ }, "/api/fleet/uninstall_tokens/{uninstallTokenId}": { "get": { - "description": "Get one decrypted uninstall token by its ID", + "description": "Get one decrypted uninstall token by its ID.", "operationId": "get-fleet-uninstall-tokens-uninstalltokenid", "parameters": [ { @@ -37367,7 +37101,7 @@ } } }, - "summary": "", + "summary": "Get a decrypted uninstall token", "tags": [ "Fleet uninstall tokens" ] diff --git a/oas_docs/bundle.serverless.json b/oas_docs/bundle.serverless.json index bc3d45fe6796..1267027a3687 100644 --- a/oas_docs/bundle.serverless.json +++ b/oas_docs/bundle.serverless.json @@ -5628,7 +5628,6 @@ }, "/api/fleet/agent_download_sources": { "get": { - "description": "List agent binary download sources", "operationId": "get-fleet-agent-download-sources", "parameters": [ { @@ -5731,13 +5730,12 @@ } } }, - "summary": "", + "summary": "Get agent binary download sources", "tags": [ "Elastic Agent binary download sources" ] }, "post": { - "description": "Create agent binary download source", "operationId": "post-fleet-agent-download-sources", "parameters": [ { @@ -5870,7 +5868,7 @@ } } }, - "summary": "", + "summary": "Create an agent binary download source", "tags": [ "Elastic Agent binary download sources" ] @@ -5878,7 +5876,7 @@ }, "/api/fleet/agent_download_sources/{sourceId}": { "delete": { - "description": "Delete agent binary download source by ID", + "description": "Delete an agent binary download source by ID.", "operationId": "delete-fleet-agent-download-sources-sourceid", "parameters": [ { @@ -5957,13 +5955,13 @@ } } }, - "summary": "", + "summary": "Delete an agent binary download source", "tags": [ "Elastic Agent binary download sources" ] }, "get": { - "description": "Get agent binary download source by ID", + "description": "Get an agent binary download source by ID.", "operationId": "get-fleet-agent-download-sources-sourceid", "parameters": [ { @@ -6059,13 +6057,13 @@ } } }, - "summary": "", + "summary": "Get an agent binary download source", "tags": [ "Elastic Agent binary download sources" ] }, "put": { - "description": "Update agent binary download source by ID", + "description": "Update an agent binary download source by ID.", "operationId": "put-fleet-agent-download-sources-sourceid", "parameters": [ { @@ -6206,7 +6204,7 @@ } } }, - "summary": "", + "summary": "Update an agent binary download source", "tags": [ "Elastic Agent binary download sources" ] @@ -6214,7 +6212,6 @@ }, "/api/fleet/agent_policies": { "get": { - "description": "List agent policies", "operationId": "get-fleet-agent-policies", "parameters": [ { @@ -7046,13 +7043,12 @@ } } }, - "summary": "", + "summary": "Get agent policies", "tags": [ "Elastic Agent policies" ] }, "post": { - "description": "Create an agent policy", "operationId": "post-fleet-agent-policies", "parameters": [ { @@ -8039,7 +8035,7 @@ } } }, - "summary": "", + "summary": "Create an agent policy", "tags": [ "Elastic Agent policies" ] @@ -8047,7 +8043,6 @@ }, "/api/fleet/agent_policies/_bulk_get": { "post": { - "description": "Bulk get agent policies", "operationId": "post-fleet-agent-policies-bulk-get", "parameters": [ { @@ -8826,7 +8821,7 @@ } } }, - "summary": "", + "summary": "Bulk get agent policies", "tags": [ "Elastic Agent policies" ] @@ -8834,7 +8829,7 @@ }, "/api/fleet/agent_policies/delete": { "post": { - "description": "Delete agent policy by ID", + "description": "Delete an agent policy by ID.", "operationId": "post-fleet-agent-policies-delete", "parameters": [ { @@ -8931,7 +8926,7 @@ } } }, - "summary": "", + "summary": "Delete an agent policy", "tags": [ "Elastic Agent policies" ] @@ -8939,7 +8934,7 @@ }, "/api/fleet/agent_policies/outputs": { "post": { - "description": "Get list of outputs associated with agent policies", + "description": "Get a list of outputs associated with agent policies.", "operationId": "post-fleet-agent-policies-outputs", "parameters": [ { @@ -9116,7 +9111,7 @@ } } }, - "summary": "", + "summary": "Get outputs for agent policies", "tags": [ "Elastic Agent policies" ] @@ -9124,7 +9119,7 @@ }, "/api/fleet/agent_policies/{agentPolicyId}": { "get": { - "description": "Get an agent policy by ID", + "description": "Get an agent policy by ID.", "operationId": "get-fleet-agent-policies-agentpolicyid", "parameters": [ { @@ -9869,13 +9864,13 @@ } } }, - "summary": "", + "summary": "Get an agent policy", "tags": [ "Elastic Agent policies" ] }, "put": { - "description": "Update an agent policy by ID", + "description": "Update an agent policy by ID.", "operationId": "put-fleet-agent-policies-agentpolicyid", "parameters": [ { @@ -10874,7 +10869,7 @@ } } }, - "summary": "", + "summary": "Update an agent policy", "tags": [ "Elastic Agent policies" ] @@ -10882,7 +10877,7 @@ }, "/api/fleet/agent_policies/{agentPolicyId}/copy": { "post": { - "description": "Copy an agent policy by ID", + "description": "Copy an agent policy by ID.", "operationId": "post-fleet-agent-policies-agentpolicyid-copy", "parameters": [ { @@ -11659,7 +11654,7 @@ } } }, - "summary": "", + "summary": "Copy an agent policy", "tags": [ "Elastic Agent policies" ] @@ -11667,7 +11662,7 @@ }, "/api/fleet/agent_policies/{agentPolicyId}/download": { "get": { - "description": "Download an agent policy by ID", + "description": "Download an agent policy by ID.", "operationId": "get-fleet-agent-policies-agentpolicyid-download", "parameters": [ { @@ -11776,7 +11771,7 @@ } } }, - "summary": "", + "summary": "Download an agent policy", "tags": [ "Elastic Agent policies" ] @@ -11784,7 +11779,7 @@ }, "/api/fleet/agent_policies/{agentPolicyId}/full": { "get": { - "description": "Get a full agent policy by ID", + "description": "Get a full agent policy by ID.", "operationId": "get-fleet-agent-policies-agentpolicyid-full", "parameters": [ { @@ -12278,7 +12273,7 @@ } } }, - "summary": "", + "summary": "Get a full agent policy", "tags": [ "Elastic Agent policies" ] @@ -12286,7 +12281,7 @@ }, "/api/fleet/agent_policies/{agentPolicyId}/outputs": { "get": { - "description": "Get list of outputs associated with agent policy by policy id", + "description": "Get a list of outputs associated with agent policy by policy id.", "operationId": "get-fleet-agent-policies-agentpolicyid-outputs", "parameters": [ { @@ -12436,7 +12431,7 @@ } } }, - "summary": "", + "summary": "Get outputs for an agent policy", "tags": [ "Elastic Agent policies" ] @@ -12444,7 +12439,6 @@ }, "/api/fleet/agent_status": { "get": { - "description": "Get agent status summary", "operationId": "get-fleet-agent-status", "parameters": [ { @@ -12584,7 +12578,7 @@ } } }, - "summary": "", + "summary": "Get an agent status summary", "tags": [ "Elastic Agent status" ] @@ -12592,7 +12586,6 @@ }, "/api/fleet/agent_status/data": { "get": { - "description": "Get incoming agent data", "operationId": "get-fleet-agent-status-data", "parameters": [ { @@ -12700,7 +12693,7 @@ } } }, - "summary": "", + "summary": "Get incoming agent data", "tags": [ "Elastic Agents" ] @@ -12708,7 +12701,6 @@ }, "/api/fleet/agents": { "get": { - "description": "List agents", "operationId": "get-fleet-agents", "parameters": [ { @@ -13253,13 +13245,12 @@ } } }, - "summary": "", + "summary": "Get agents", "tags": [ "Elastic Agents" ] }, "post": { - "description": "List agents by action ids", "operationId": "post-fleet-agents", "parameters": [ { @@ -13354,7 +13345,7 @@ } } }, - "summary": "", + "summary": "Get agents by action ids", "tags": [ "Elastic Agents" ] @@ -13362,7 +13353,6 @@ }, "/api/fleet/agents/action_status": { "get": { - "description": "Get agent action status", "operationId": "get-fleet-agents-action-status", "parameters": [ { @@ -13590,7 +13580,7 @@ } } }, - "summary": "", + "summary": "Get an agent action status", "tags": [ "Elastic Agent actions" ] @@ -13598,7 +13588,6 @@ }, "/api/fleet/agents/actions/{actionId}/cancel": { "post": { - "description": "Cancel agent action", "operationId": "post-fleet-agents-actions-actionid-cancel", "parameters": [ { @@ -13732,7 +13721,7 @@ } } }, - "summary": "", + "summary": "Cancel an agent action", "tags": [ "Elastic Agent actions" ] @@ -13740,7 +13729,6 @@ }, "/api/fleet/agents/available_versions": { "get": { - "description": "Get available agent versions", "operationId": "get-fleet-agents-available-versions", "parameters": [ { @@ -13804,7 +13792,7 @@ } } }, - "summary": "", + "summary": "Get available agent versions", "tags": [ "Elastic Agents" ] @@ -13812,7 +13800,6 @@ }, "/api/fleet/agents/bulk_reassign": { "post": { - "description": "Bulk reassign agents", "operationId": "post-fleet-agents-bulk-reassign", "parameters": [ { @@ -13922,7 +13909,7 @@ } } }, - "summary": "", + "summary": "Bulk reassign agents", "tags": [ "Elastic Agent actions" ] @@ -13930,7 +13917,6 @@ }, "/api/fleet/agents/bulk_request_diagnostics": { "post": { - "description": "Bulk request diagnostics from agents", "operationId": "post-fleet-agents-bulk-request-diagnostics", "parameters": [ { @@ -14041,7 +14027,7 @@ } } }, - "summary": "", + "summary": "Bulk request diagnostics from agents", "tags": [ "Elastic Agent actions" ] @@ -14049,7 +14035,6 @@ }, "/api/fleet/agents/bulk_unenroll": { "post": { - "description": "Bulk unenroll agents", "operationId": "post-fleet-agents-bulk-unenroll", "parameters": [ { @@ -14165,7 +14150,7 @@ } } }, - "summary": "", + "summary": "Bulk unenroll agents", "tags": [ "Elastic Agent actions" ] @@ -14173,7 +14158,6 @@ }, "/api/fleet/agents/bulk_update_agent_tags": { "post": { - "description": "Bulk update agent tags", "operationId": "post-fleet-agents-bulk-update-agent-tags", "parameters": [ { @@ -14291,7 +14275,7 @@ } } }, - "summary": "", + "summary": "Bulk update agent tags", "tags": [ "Elastic Agent actions" ] @@ -14299,7 +14283,6 @@ }, "/api/fleet/agents/bulk_upgrade": { "post": { - "description": "Bulk upgrade agents", "operationId": "post-fleet-agents-bulk-upgrade", "parameters": [ { @@ -14425,7 +14408,7 @@ } } }, - "summary": "", + "summary": "Bulk upgrade agents", "tags": [ "Elastic Agent actions" ] @@ -14433,7 +14416,7 @@ }, "/api/fleet/agents/files/{fileId}": { "delete": { - "description": "Delete file uploaded by agent", + "description": "Delete a file uploaded by an agent.", "operationId": "delete-fleet-agents-files-fileid", "parameters": [ { @@ -14516,7 +14499,7 @@ } } }, - "summary": "", + "summary": "Delete an uploaded file", "tags": [ "Elastic Agents" ] @@ -14524,7 +14507,7 @@ }, "/api/fleet/agents/files/{fileId}/{fileName}": { "get": { - "description": "Get file uploaded by agent", + "description": "Get a file uploaded by an agent.", "operationId": "get-fleet-agents-files-fileid-filename", "parameters": [ { @@ -14592,7 +14575,7 @@ } } }, - "summary": "", + "summary": "Get an uploaded file", "tags": [ "Elastic Agents" ] @@ -14600,7 +14583,6 @@ }, "/api/fleet/agents/setup": { "get": { - "description": "Get agent setup info", "operationId": "get-fleet-agents-setup", "parameters": [ { @@ -14695,13 +14677,12 @@ } } }, - "summary": "", + "summary": "Get agent setup info", "tags": [ "Elastic Agents" ] }, "post": { - "description": "Initiate agent setup", "operationId": "post-fleet-agents-setup", "parameters": [ { @@ -14793,7 +14774,7 @@ } } }, - "summary": "", + "summary": "Initiate agent setup", "tags": [ "Elastic Agents" ] @@ -14801,7 +14782,6 @@ }, "/api/fleet/agents/tags": { "get": { - "description": "List agent tags", "operationId": "get-fleet-agents-tags", "parameters": [ { @@ -14882,7 +14862,7 @@ } } }, - "summary": "", + "summary": "Get agent tags", "tags": [ "Elastic Agents" ] @@ -14890,7 +14870,7 @@ }, "/api/fleet/agents/{agentId}": { "delete": { - "description": "Delete agent by ID", + "description": "Delete an agent by ID.", "operationId": "delete-fleet-agents-agentid", "parameters": [ { @@ -14972,13 +14952,13 @@ } } }, - "summary": "", + "summary": "Delete an agent", "tags": [ "Elastic Agents" ] }, "get": { - "description": "Get agent by ID", + "description": "Get an agent by ID.", "operationId": "get-fleet-agents-agentid", "parameters": [ { @@ -15437,13 +15417,13 @@ } } }, - "summary": "", + "summary": "Get an agent", "tags": [ "Elastic Agents" ] }, "put": { - "description": "Update agent by ID", + "description": "Update an agent by ID.", "operationId": "put-fleet-agents-agentid", "parameters": [ { @@ -15925,7 +15905,7 @@ } } }, - "summary": "", + "summary": "Update an agent", "tags": [ "Elastic Agents" ] @@ -15933,7 +15913,6 @@ }, "/api/fleet/agents/{agentId}/actions": { "post": { - "description": "Create agent action", "operationId": "post-fleet-agents-agentid-actions", "parameters": [ { @@ -16142,7 +16121,7 @@ } } }, - "summary": "", + "summary": "Create an agent action", "tags": [ "Elastic Agent actions" ] @@ -16150,7 +16129,6 @@ }, "/api/fleet/agents/{agentId}/reassign": { "post": { - "description": "Reassign agent", "operationId": "post-fleet-agents-agentid-reassign", "parameters": [ { @@ -16240,7 +16218,7 @@ } } }, - "summary": "", + "summary": "Reassign an agent", "tags": [ "Elastic Agent actions" ] @@ -16248,7 +16226,6 @@ }, "/api/fleet/agents/{agentId}/request_diagnostics": { "post": { - "description": "Request agent diagnostics", "operationId": "post-fleet-agents-agentid-request-diagnostics", "parameters": [ { @@ -16349,7 +16326,7 @@ } } }, - "summary": "", + "summary": "Request agent diagnostics", "tags": [ "Elastic Agent actions" ] @@ -16357,7 +16334,6 @@ }, "/api/fleet/agents/{agentId}/unenroll": { "post": { - "description": "Unenroll agent", "operationId": "post-fleet-agents-agentid-unenroll", "parameters": [ { @@ -16411,7 +16387,7 @@ } }, "responses": {}, - "summary": "", + "summary": "Unenroll an agent", "tags": [ "Elastic Agent actions" ] @@ -16419,7 +16395,6 @@ }, "/api/fleet/agents/{agentId}/upgrade": { "post": { - "description": "Upgrade agent", "operationId": "post-fleet-agents-agentid-upgrade", "parameters": [ { @@ -16518,7 +16493,7 @@ } } }, - "summary": "", + "summary": "Upgrade an agent", "tags": [ "Elastic Agent actions" ] @@ -16526,7 +16501,6 @@ }, "/api/fleet/agents/{agentId}/uploads": { "get": { - "description": "List agent uploads", "operationId": "get-fleet-agents-agentid-uploads", "parameters": [ { @@ -16638,7 +16612,7 @@ } } }, - "summary": "", + "summary": "Get agent uploads", "tags": [ "Elastic Agents" ] @@ -16646,7 +16620,6 @@ }, "/api/fleet/check-permissions": { "get": { - "description": "Check permissions", "operationId": "get-fleet-check-permissions", "parameters": [ { @@ -16723,7 +16696,7 @@ } } }, - "summary": "", + "summary": "Check permissions", "tags": [ "Fleet internals" ] @@ -16731,7 +16704,6 @@ }, "/api/fleet/data_streams": { "get": { - "description": "List data streams", "operationId": "get-fleet-data-streams", "parameters": [ { @@ -16881,7 +16853,7 @@ } } }, - "summary": "", + "summary": "Get data streams", "tags": [ "Data streams" ] @@ -16889,7 +16861,6 @@ }, "/api/fleet/enrollment_api_keys": { "get": { - "description": "List enrollment API keys", "operationId": "get-fleet-enrollment-api-keys", "parameters": [ { @@ -17027,13 +16998,12 @@ } } }, - "summary": "", + "summary": "Get enrollment API keys", "tags": [ "Fleet enrollment API keys" ] }, "post": { - "description": "Create enrollment API key", "operationId": "post-fleet-enrollment-api-keys", "parameters": [ { @@ -17171,7 +17141,7 @@ } } }, - "summary": "", + "summary": "Create an enrollment API key", "tags": [ "Fleet enrollment API keys" ] @@ -17179,7 +17149,7 @@ }, "/api/fleet/enrollment_api_keys/{keyId}": { "delete": { - "description": "Revoke enrollment API key by ID by marking it as inactive", + "description": "Revoke an enrollment API key by ID by marking it as inactive.", "operationId": "delete-fleet-enrollment-api-keys-keyid", "parameters": [ { @@ -17261,13 +17231,13 @@ } } }, - "summary": "", + "summary": "Revoke an enrollment API key", "tags": [ "Fleet enrollment API keys" ] }, "get": { - "description": "Get enrollment API key by ID", + "description": "Get an enrollment API key by ID.", "operationId": "get-fleet-enrollment-api-keys-keyid", "parameters": [ { @@ -17372,7 +17342,7 @@ } } }, - "summary": "", + "summary": "Get an enrollment API key", "tags": [ "Fleet enrollment API keys" ] @@ -17380,7 +17350,6 @@ }, "/api/fleet/epm/bulk_assets": { "post": { - "description": "Bulk get assets", "operationId": "post-fleet-epm-bulk-assets", "parameters": [ { @@ -17523,7 +17492,7 @@ } } }, - "summary": "", + "summary": "Bulk get assets", "tags": [ "Elastic Package Manager (EPM)" ] @@ -17531,7 +17500,6 @@ }, "/api/fleet/epm/categories": { "get": { - "description": "List package categories", "operationId": "get-fleet-epm-categories", "parameters": [ { @@ -17634,7 +17602,7 @@ } } }, - "summary": "", + "summary": "Get package categories", "tags": [ "Elastic Package Manager (EPM)" ] @@ -17642,7 +17610,6 @@ }, "/api/fleet/epm/custom_integrations": { "post": { - "description": "Create custom integration", "operationId": "post-fleet-epm-custom-integrations", "parameters": [ { @@ -17843,7 +17810,7 @@ } } }, - "summary": "", + "summary": "Create a custom integration", "tags": [ "Elastic Package Manager (EPM)" ] @@ -17851,7 +17818,6 @@ }, "/api/fleet/epm/data_streams": { "get": { - "description": "List data streams", "operationId": "get-fleet-epm-data-streams", "parameters": [ { @@ -17969,7 +17935,7 @@ } } }, - "summary": "", + "summary": "Get data streams", "tags": [ "Data streams" ] @@ -17977,7 +17943,6 @@ }, "/api/fleet/epm/packages": { "get": { - "description": "List packages", "operationId": "get-fleet-epm-packages", "parameters": [ { @@ -18543,13 +18508,12 @@ } } }, - "summary": "", + "summary": "Get packages", "tags": [ "Elastic Package Manager (EPM)" ] }, "post": { - "description": "Install package by upload", "operationId": "post-fleet-epm-packages", "parameters": [ { @@ -18730,7 +18694,7 @@ } } }, - "summary": "", + "summary": "Install a package by upload", "tags": [ "Elastic Package Manager (EPM)" ] @@ -18738,7 +18702,6 @@ }, "/api/fleet/epm/packages/_bulk": { "post": { - "description": "Bulk install packages", "operationId": "post-fleet-epm-packages-bulk", "parameters": [ { @@ -19008,7 +18971,7 @@ } } }, - "summary": "", + "summary": "Bulk install packages", "tags": [ "Elastic Package Manager (EPM)" ] @@ -19016,7 +18979,6 @@ }, "/api/fleet/epm/packages/installed": { "get": { - "description": "Get installed packages", "operationId": "get-fleet-epm-packages-installed", "parameters": [ { @@ -19249,7 +19211,7 @@ } } }, - "summary": "", + "summary": "Get installed packages", "tags": [ "Elastic Package Manager (EPM)" ] @@ -19257,7 +19219,6 @@ }, "/api/fleet/epm/packages/limited": { "get": { - "description": "Get limited package list", "operationId": "get-fleet-epm-packages-limited", "parameters": [ { @@ -19321,7 +19282,7 @@ } } }, - "summary": "", + "summary": "Get a limited package list", "tags": [ "Elastic Package Manager (EPM)" ] @@ -19329,7 +19290,6 @@ }, "/api/fleet/epm/packages/{pkgName}/stats": { "get": { - "description": "Get package stats", "operationId": "get-fleet-epm-packages-pkgname-stats", "parameters": [ { @@ -19407,7 +19367,7 @@ } } }, - "summary": "", + "summary": "Get package stats", "tags": [ "Elastic Package Manager (EPM)" ] @@ -19415,7 +19375,6 @@ }, "/api/fleet/epm/packages/{pkgName}/{pkgVersion}": { "delete": { - "description": "Delete package", "operationId": "delete-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { @@ -19579,13 +19538,12 @@ } } }, - "summary": "", + "summary": "Delete a package", "tags": [ "Elastic Package Manager (EPM)" ] }, "get": { - "description": "Get package", "operationId": "get-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { @@ -20271,13 +20229,12 @@ } } }, - "summary": "", + "summary": "Get a package", "tags": [ "Elastic Package Manager (EPM)" ] }, "post": { - "description": "Install package from registry", "operationId": "post-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { @@ -20493,13 +20450,12 @@ } } }, - "summary": "", + "summary": "Install a package from the registry", "tags": [ "Elastic Package Manager (EPM)" ] }, "put": { - "description": "Update package settings", "operationId": "put-fleet-epm-packages-pkgname-pkgversion", "parameters": [ { @@ -21168,7 +21124,7 @@ } } }, - "summary": "", + "summary": "Update package settings", "tags": [ "Elastic Package Manager (EPM)" ] @@ -21176,7 +21132,6 @@ }, "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/transforms/authorize": { "post": { - "description": "Authorize transforms", "operationId": "post-fleet-epm-packages-pkgname-pkgversion-transforms-authorize", "parameters": [ { @@ -21312,7 +21267,7 @@ } } }, - "summary": "", + "summary": "Authorize transforms", "tags": [ "Elastic Package Manager (EPM)" ] @@ -21320,7 +21275,6 @@ }, "/api/fleet/epm/packages/{pkgName}/{pkgVersion}/{filePath*}": { "get": { - "description": "Get package file", "operationId": "get-fleet-epm-packages-pkgname-pkgversion-filepath", "parameters": [ { @@ -21394,7 +21348,7 @@ } } }, - "summary": "", + "summary": "Get a package file", "tags": [ "Elastic Package Manager (EPM)" ] @@ -21402,7 +21356,6 @@ }, "/api/fleet/epm/templates/{pkgName}/{pkgVersion}/inputs": { "get": { - "description": "Get inputs template", "operationId": "get-fleet-epm-templates-pkgname-pkgversion-inputs", "parameters": [ { @@ -21563,7 +21516,7 @@ } } }, - "summary": "", + "summary": "Get an inputs template", "tags": [ "Elastic Package Manager (EPM)" ] @@ -21571,7 +21524,6 @@ }, "/api/fleet/epm/verification_key_id": { "get": { - "description": "Get a package signature verification key ID", "operationId": "get-fleet-epm-verification-key-id", "parameters": [ { @@ -21633,7 +21585,7 @@ } } }, - "summary": "", + "summary": "Get a package signature verification key ID", "tags": [ "Elastic Package Manager (EPM)" ] @@ -21641,7 +21593,6 @@ }, "/api/fleet/fleet_server_hosts": { "get": { - "description": "List Fleet Server hosts", "operationId": "get-fleet-fleet-server-hosts", "parameters": [ { @@ -21753,13 +21704,12 @@ } } }, - "summary": "", + "summary": "Get Fleet Server hosts", "tags": [ "Fleet Server hosts" ] }, "post": { - "description": "Create Fleet Server host", "operationId": "post-fleet-fleet-server-hosts", "parameters": [ { @@ -21910,7 +21860,7 @@ } } }, - "summary": "", + "summary": "Create a Fleet Server host", "tags": [ "Fleet Server hosts" ] @@ -21918,7 +21868,7 @@ }, "/api/fleet/fleet_server_hosts/{itemId}": { "delete": { - "description": "Delete Fleet Server host by ID", + "description": "Delete a Fleet Server host by ID.", "operationId": "delete-fleet-fleet-server-hosts-itemid", "parameters": [ { @@ -21997,13 +21947,13 @@ } } }, - "summary": "", + "summary": "Delete a Fleet Server host", "tags": [ "Fleet Server hosts" ] }, "get": { - "description": "Get Fleet Server host by ID", + "description": "Get a Fleet Server host by ID.", "operationId": "get-fleet-fleet-server-hosts-itemid", "parameters": [ { @@ -22108,13 +22058,13 @@ } } }, - "summary": "", + "summary": "Get a Fleet Server host", "tags": [ "Fleet Server hosts" ] }, "put": { - "description": "Update Fleet Server host by ID", + "description": "Update a Fleet Server host by ID.", "operationId": "put-fleet-fleet-server-hosts-itemid", "parameters": [ { @@ -22264,7 +22214,7 @@ } } }, - "summary": "", + "summary": "Update a Fleet Server host", "tags": [ "Fleet Server hosts" ] @@ -22272,7 +22222,6 @@ }, "/api/fleet/health_check": { "post": { - "description": "Check Fleet Server health", "operationId": "post-fleet-health-check", "parameters": [ { @@ -22392,7 +22341,7 @@ } } }, - "summary": "", + "summary": "Check Fleet Server health", "tags": [ "Fleet internals" ] @@ -22400,7 +22349,6 @@ }, "/api/fleet/kubernetes": { "get": { - "description": "Get full K8s agent manifest", "operationId": "get-fleet-kubernetes", "parameters": [ { @@ -22485,7 +22433,7 @@ } } }, - "summary": "", + "summary": "Get a full K8s agent manifest", "tags": [ "Elastic Agent policies" ] @@ -22593,7 +22541,7 @@ } } }, - "summary": "", + "summary": "Download an agent manifest", "tags": [ "Elastic Agent policies" ] @@ -22601,7 +22549,6 @@ }, "/api/fleet/logstash_api_keys": { "post": { - "description": "Generate Logstash API key", "operationId": "post-fleet-logstash-api-keys", "parameters": [ { @@ -22672,7 +22619,7 @@ } } }, - "summary": "", + "summary": "Generate a Logstash API key", "tags": [ "Fleet outputs" ] @@ -22680,7 +22627,6 @@ }, "/api/fleet/message_signing_service/rotate_key_pair": { "post": { - "description": "Rotate fleet message signing key pair", "operationId": "post-fleet-message-signing-service-rotate-key-pair", "parameters": [ { @@ -22785,7 +22731,7 @@ } } }, - "summary": "", + "summary": "Rotate a Fleet message signing key pair", "tags": [ "Message Signing Service" ] @@ -22793,7 +22739,6 @@ }, "/api/fleet/outputs": { "get": { - "description": "List outputs", "operationId": "get-fleet-outputs", "parameters": [ { @@ -23782,39 +23727,6 @@ "topic": { "type": "string" }, - "topics": { - "items": { - "additionalProperties": true, - "properties": { - "topic": { - "type": "string" - }, - "when": { - "additionalProperties": true, - "properties": { - "condition": { - "type": "string" - }, - "type": { - "enum": [ - "equals", - "contains", - "regexp" - ], - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "topic" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, "type": { "enum": [ "kafka" @@ -23917,13 +23829,12 @@ } } }, - "summary": "", + "summary": "Get outputs", "tags": [ "Fleet outputs" ] }, "post": { - "description": "Create output", "operationId": "post-fleet-outputs", "parameters": [ { @@ -24917,39 +24828,6 @@ "topic": { "type": "string" }, - "topics": { - "items": { - "additionalProperties": false, - "properties": { - "topic": { - "type": "string" - }, - "when": { - "additionalProperties": false, - "properties": { - "condition": { - "type": "string" - }, - "type": { - "enum": [ - "equals", - "contains", - "regexp" - ], - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "topic" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, "type": { "enum": [ "kafka" @@ -25978,39 +25856,6 @@ "topic": { "type": "string" }, - "topics": { - "items": { - "additionalProperties": true, - "properties": { - "topic": { - "type": "string" - }, - "when": { - "additionalProperties": true, - "properties": { - "condition": { - "type": "string" - }, - "type": { - "enum": [ - "equals", - "contains", - "regexp" - ], - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "topic" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, "type": { "enum": [ "kafka" @@ -26099,7 +25944,7 @@ } } }, - "summary": "", + "summary": "Create output", "tags": [ "Fleet outputs" ] @@ -26107,7 +25952,7 @@ }, "/api/fleet/outputs/{outputId}": { "delete": { - "description": "Delete output by ID", + "description": "Delete output by ID.", "operationId": "delete-fleet-outputs-outputid", "parameters": [ { @@ -26211,13 +26056,13 @@ } } }, - "summary": "", + "summary": "Delete output", "tags": [ "Fleet outputs" ] }, "get": { - "description": "Get output by ID", + "description": "Get output by ID.", "operationId": "get-fleet-outputs-outputid", "parameters": [ { @@ -27213,39 +27058,6 @@ "topic": { "type": "string" }, - "topics": { - "items": { - "additionalProperties": true, - "properties": { - "topic": { - "type": "string" - }, - "when": { - "additionalProperties": true, - "properties": { - "condition": { - "type": "string" - }, - "type": { - "enum": [ - "equals", - "contains", - "regexp" - ], - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "topic" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, "type": { "enum": [ "kafka" @@ -27334,13 +27146,13 @@ } } }, - "summary": "", + "summary": "Get output", "tags": [ "Fleet outputs" ] }, "put": { - "description": "Update output by ID", + "description": "Update output by ID.", "operationId": "put-fleet-outputs-outputid", "parameters": [ { @@ -28321,39 +28133,6 @@ "topic": { "type": "string" }, - "topics": { - "items": { - "additionalProperties": false, - "properties": { - "topic": { - "type": "string" - }, - "when": { - "additionalProperties": false, - "properties": { - "condition": { - "type": "string" - }, - "type": { - "enum": [ - "equals", - "contains", - "regexp" - ], - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "topic" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, "type": { "enum": [ "kafka" @@ -29379,39 +29158,6 @@ "topic": { "type": "string" }, - "topics": { - "items": { - "additionalProperties": true, - "properties": { - "topic": { - "type": "string" - }, - "when": { - "additionalProperties": true, - "properties": { - "condition": { - "type": "string" - }, - "type": { - "enum": [ - "equals", - "contains", - "regexp" - ], - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "topic" - ], - "type": "object" - }, - "minItems": 1, - "type": "array" - }, "type": { "enum": [ "kafka" @@ -29500,7 +29246,7 @@ } } }, - "summary": "", + "summary": "Update output", "tags": [ "Fleet outputs" ] @@ -29508,7 +29254,6 @@ }, "/api/fleet/outputs/{outputId}/health": { "get": { - "description": "Get latest output health", "operationId": "get-fleet-outputs-outputid-health", "parameters": [ { @@ -29588,7 +29333,7 @@ } } }, - "summary": "", + "summary": "Get the latest output health", "tags": [ "Fleet outputs" ] @@ -29596,7 +29341,6 @@ }, "/api/fleet/package_policies": { "get": { - "description": "List package policies", "operationId": "get-fleet-package-policies", "parameters": [ { @@ -30305,13 +30049,12 @@ } } }, - "summary": "", + "summary": "Get package policies", "tags": [ "Fleet package policies" ] }, "post": { - "description": "Create package policy", "operationId": "post-fleet-package-policies", "parameters": [ { @@ -31577,7 +31320,7 @@ } } }, - "summary": "", + "summary": "Create a package policy", "tags": [ "Fleet package policies" ] @@ -31585,7 +31328,6 @@ }, "/api/fleet/package_policies/_bulk_get": { "post": { - "description": "Bulk get package policies", "operationId": "post-fleet-package-policies-bulk-get", "parameters": [ { @@ -32275,7 +32017,7 @@ } } }, - "summary": "", + "summary": "Bulk get package policies", "tags": [ "Fleet package policies" ] @@ -32283,7 +32025,6 @@ }, "/api/fleet/package_policies/delete": { "post": { - "description": "Bulk delete package policies", "operationId": "post-fleet-package-policies-delete", "parameters": [ { @@ -32479,7 +32220,7 @@ } } }, - "summary": "", + "summary": "Bulk delete package policies", "tags": [ "Fleet package policies" ] @@ -32487,7 +32228,7 @@ }, "/api/fleet/package_policies/upgrade": { "post": { - "description": "Upgrade package policy to a newer package version", + "description": "Upgrade a package policy to a newer package version.", "operationId": "post-fleet-package-policies-upgrade", "parameters": [ { @@ -32604,7 +32345,7 @@ } } }, - "summary": "", + "summary": "Upgrade a package policy", "tags": [ "Fleet package policies" ] @@ -32612,7 +32353,6 @@ }, "/api/fleet/package_policies/upgrade/dryrun": { "post": { - "description": "Dry run package policy upgrade", "operationId": "post-fleet-package-policies-upgrade-dryrun", "parameters": [ { @@ -33790,7 +33530,7 @@ } } }, - "summary": "", + "summary": "Dry run a package policy upgrade", "tags": [ "Fleet package policies" ] @@ -33798,7 +33538,7 @@ }, "/api/fleet/package_policies/{packagePolicyId}": { "delete": { - "description": "Delete package policy by ID", + "description": "Delete a package policy by ID.", "operationId": "delete-fleet-package-policies-packagepolicyid", "parameters": [ { @@ -33885,13 +33625,13 @@ } } }, - "summary": "", + "summary": "Delete a package policy", "tags": [ "Fleet package policies" ] }, "get": { - "description": "Get package policy by ID", + "description": "Get a package policy by ID.", "operationId": "get-fleet-package-policies-packagepolicyid", "parameters": [ { @@ -34551,13 +34291,13 @@ } } }, - "summary": "", + "summary": "Get a package policy", "tags": [ "Fleet package policies" ] }, "put": { - "description": "Update package policy by ID", + "description": "Update a package policy by ID.", "operationId": "put-fleet-package-policies-packagepolicyid", "parameters": [ { @@ -35823,7 +35563,7 @@ } } }, - "summary": "", + "summary": "Update a package policy", "tags": [ "Fleet package policies" ] @@ -35831,7 +35571,6 @@ }, "/api/fleet/proxies": { "get": { - "description": "List proxies", "operationId": "get-fleet-proxies", "parameters": [ { @@ -35957,13 +35696,12 @@ } } }, - "summary": "", + "summary": "Get proxies", "tags": [ "Fleet proxies" ] }, "post": { - "description": "Create proxy", "operationId": "post-fleet-proxies", "parameters": [ { @@ -36142,7 +35880,7 @@ } } }, - "summary": "", + "summary": "Create a proxy", "tags": [ "Fleet proxies" ] @@ -36150,7 +35888,7 @@ }, "/api/fleet/proxies/{itemId}": { "delete": { - "description": "Delete proxy by ID", + "description": "Delete a proxy by ID", "operationId": "delete-fleet-proxies-itemid", "parameters": [ { @@ -36229,13 +35967,13 @@ } } }, - "summary": "", + "summary": "Delete a proxy", "tags": [ "Fleet proxies" ] }, "get": { - "description": "Get proxy by ID", + "description": "Get a proxy by ID.", "operationId": "get-fleet-proxies-itemid", "parameters": [ { @@ -36354,13 +36092,13 @@ } } }, - "summary": "", + "summary": "Get a proxy", "tags": [ "Fleet proxies" ] }, "put": { - "description": "Update proxy by ID", + "description": "Update a proxy by ID.", "operationId": "put-fleet-proxies-itemid", "parameters": [ { @@ -36542,7 +36280,7 @@ } } }, - "summary": "", + "summary": "Update a proxy", "tags": [ "Fleet proxies" ] @@ -36550,7 +36288,6 @@ }, "/api/fleet/service_tokens": { "post": { - "description": "Create a service token", "operationId": "post-fleet-service-tokens", "parameters": [ { @@ -36642,7 +36379,7 @@ } } }, - "summary": "", + "summary": "Create a service token", "tags": [ "Fleet service tokens" ] @@ -36650,7 +36387,6 @@ }, "/api/fleet/settings": { "get": { - "description": "Get settings", "operationId": "get-fleet-settings", "parameters": [ { @@ -36789,13 +36525,12 @@ } } }, - "summary": "", + "summary": "Get settings", "tags": [ "Fleet internals" ] }, "put": { - "description": "Update settings", "operationId": "put-fleet-settings", "parameters": [ { @@ -36991,7 +36726,7 @@ } } }, - "summary": "", + "summary": "Update settings", "tags": [ "Fleet internals" ] @@ -36999,7 +36734,6 @@ }, "/api/fleet/setup": { "post": { - "description": "Initiate Fleet setup", "operationId": "post-fleet-setup", "parameters": [ { @@ -37110,7 +36844,7 @@ } } }, - "summary": "", + "summary": "Initiate Fleet setup", "tags": [ "Fleet internals" ] @@ -37118,7 +36852,7 @@ }, "/api/fleet/uninstall_tokens": { "get": { - "description": "List metadata for latest uninstall tokens per agent policy", + "description": "List the metadata for the latest uninstall tokens per agent policy.", "operationId": "get-fleet-uninstall-tokens", "parameters": [ { @@ -37259,7 +36993,7 @@ } } }, - "summary": "", + "summary": "Get metadata for latest uninstall tokens", "tags": [ "Fleet uninstall tokens" ] @@ -37267,7 +37001,7 @@ }, "/api/fleet/uninstall_tokens/{uninstallTokenId}": { "get": { - "description": "Get one decrypted uninstall token by its ID", + "description": "Get one decrypted uninstall token by its ID.", "operationId": "get-fleet-uninstall-tokens-uninstalltokenid", "parameters": [ { @@ -37367,7 +37101,7 @@ } } }, - "summary": "", + "summary": "Get a decrypted uninstall token", "tags": [ "Fleet uninstall tokens" ] diff --git a/oas_docs/.spectral.yaml b/oas_docs/linters/.spectral.yaml similarity index 100% rename from oas_docs/.spectral.yaml rename to oas_docs/linters/.spectral.yaml diff --git a/oas_docs/linters/redocly.yaml b/oas_docs/linters/redocly.yaml new file mode 100644 index 000000000000..139a503ba856 --- /dev/null +++ b/oas_docs/linters/redocly.yaml @@ -0,0 +1,52 @@ +extends: + - recommended +rules: +# Built-in rules + # Descriptions + parameter-description: warn + tag-description: warn + operation-description: off + # Document info + info-contact: warn + info-license: warn + # Examples + no-invalid-media-type-examples: + severity: warn + allowAdditionalProperties: false + no-invalid-schema-examples: + severity: warn + allowAdditionalProperties: false + # Operations + operation-operationId: error + operation-operationId-unique: error + operation-operationId-url-safe: warn + operation-summary: warn + # Parameters + path-parameters-defined: warn + # Paths + no-ambiguous-paths: warn + no-identical-paths: error + path-excludes-patterns: + severity: error + patterns: + - ^\/internal + # Responses + operation-4xx-response: off + operation-2xx-response: off + # Schema + spec: off + spec-strict-refs: off + # Tags + operation-tag-defined: off + tags-alphabetical: off + operation-singular-tag: off +# Custom rules + rule/operation-summary-length: + subject: + type: Operation + property: summary + message: Operation summary must have a minimum of 5 and maximum of 45 characters + severity: warn + assertions: + maxLength: 45 + minLength: 5 \ No newline at end of file diff --git a/oas_docs/makefile b/oas_docs/makefile index 85ab06e0c2c7..2ea80877771c 100644 --- a/oas_docs/makefile +++ b/oas_docs/makefile @@ -27,20 +27,16 @@ api-docs-serverless: ## Generate only kibana.serverless.yaml @node scripts/merge_serverless_oas.js .PHONY: api-docs-lint -api-docs-lint: ## Run spectral API docs linter - @npx @stoplight/spectral-cli lint "output/*.yaml" --ruleset ".spectral.yaml" - -.PHONY: api-docs-lint-errs -api-docs-lint-errs: ## Run spectral API docs linter and return only errors - @npx @stoplight/spectral-cli lint "output/*.yaml" --ruleset ".spectral.yaml" -D +api-docs-lint: ## Run redocly API docs linter + @npx @redocly/cli lint "output/*.yaml" --config "linters/redocly.yaml" --format stylish --max-problems 500 .PHONY: api-docs-lint-stateful -api-docs-lint-stateful: ## Run spectral API docs linter on kibana.yaml - @npx @stoplight/spectral-cli lint "output/kibana.yaml" --ruleset ".spectral.yaml" +api-docs-lint-stateful: ## Run redocly API docs linter on kibana.yaml + @npx @redocly/cli lint "output/kibana.yaml" --config "linters/redocly.yaml" --format stylish --max-problems 500 .PHONY: api-docs-lint-serverless -api-docs-lint-serverless: ## Run spectral API docs linter on kibana.serverless.yaml - @npx @stoplight/spectral-cli lint "output/kibana.serverless.yaml" --ruleset ".spectral.yaml" +api-docs-lint-serverless: ## Run redocly API docs linter on kibana.serverless.yaml + @npx @redocly/cli lint "output/kibana.serverless.yaml" --config "linters/redocly.yaml" --format stylish --max-problems 500 .PHONY: api-docs-overlay api-docs-overlay: ## Run spectral API docs linter on kibana.serverless.yaml diff --git a/oas_docs/output/kibana.serverless.staging.yaml b/oas_docs/output/kibana.serverless.staging.yaml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/oas_docs/output/kibana.serverless.yaml b/oas_docs/output/kibana.serverless.yaml index 78c8541059d2..5f18154db449 100644 --- a/oas_docs/output/kibana.serverless.yaml +++ b/oas_docs/output/kibana.serverless.yaml @@ -9870,7 +9870,6 @@ paths: - Security Exceptions API /api/fleet/agent_download_sources: get: - description: List agent binary download sources operationId: get-fleet-agent-download-sources parameters: - description: The version of the API to use @@ -9942,11 +9941,10 @@ paths: type: number required: - message - summary: '' + summary: Get agent binary download sources tags: - Elastic Agent binary download sources post: - description: Create agent binary download source operationId: post-fleet-agent-download-sources parameters: - description: The version of the API to use @@ -10040,12 +10038,12 @@ paths: type: number required: - message - summary: '' + summary: Create an agent binary download source tags: - Elastic Agent binary download sources /api/fleet/agent_download_sources/{sourceId}: delete: - description: Delete agent binary download source by ID + description: Delete an agent binary download source by ID. operationId: delete-fleet-agent-download-sources-sourceid parameters: - description: The version of the API to use @@ -10096,11 +10094,11 @@ paths: type: number required: - message - summary: '' + summary: Delete an agent binary download source tags: - Elastic Agent binary download sources get: - description: Get agent binary download source by ID + description: Get an agent binary download source by ID. operationId: get-fleet-agent-download-sources-sourceid parameters: - description: The version of the API to use @@ -10166,11 +10164,11 @@ paths: type: number required: - message - summary: '' + summary: Get an agent binary download source tags: - Elastic Agent binary download sources put: - description: Update agent binary download source by ID + description: Update an agent binary download source by ID. operationId: put-fleet-agent-download-sources-sourceid parameters: - description: The version of the API to use @@ -10269,12 +10267,11 @@ paths: type: number required: - message - summary: '' + summary: Update an agent binary download source tags: - Elastic Agent binary download sources /api/fleet/agent_policies: get: - description: List agent policies operationId: get-fleet-agent-policies parameters: - description: The version of the API to use @@ -10884,11 +10881,10 @@ paths: type: number required: - message - summary: '' + summary: Get agent policies tags: - Elastic Agent policies post: - description: Create an agent policy operationId: post-fleet-agent-policies parameters: - description: The version of the API to use @@ -11618,12 +11614,11 @@ paths: type: number required: - message - summary: '' + summary: Create an agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/_bulk_get: post: - description: Bulk get agent policies operationId: post-fleet-agent-policies-bulk-get parameters: - description: The version of the API to use @@ -12198,12 +12193,12 @@ paths: type: number required: - message - summary: '' + summary: Bulk get agent policies tags: - Elastic Agent policies /api/fleet/agent_policies/{agentPolicyId}: get: - description: Get an agent policy by ID + description: Get an agent policy by ID. operationId: get-fleet-agent-policies-agentpolicyid parameters: - description: The version of the API to use @@ -12755,11 +12750,11 @@ paths: type: number required: - message - summary: '' + summary: Get an agent policy tags: - Elastic Agent policies put: - description: Update an agent policy by ID + description: Update an agent policy by ID. operationId: put-fleet-agent-policies-agentpolicyid parameters: - description: The version of the API to use @@ -13497,12 +13492,12 @@ paths: type: number required: - message - summary: '' + summary: Update an agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/{agentPolicyId}/copy: post: - description: Copy an agent policy by ID + description: Copy an agent policy by ID. operationId: post-fleet-agent-policies-agentpolicyid-copy parameters: - description: The version of the API to use @@ -14075,12 +14070,12 @@ paths: type: number required: - message - summary: '' + summary: Copy an agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/{agentPolicyId}/download: get: - description: Download an agent policy by ID + description: Download an agent policy by ID. operationId: get-fleet-agent-policies-agentpolicyid-download parameters: - description: The version of the API to use @@ -14149,12 +14144,12 @@ paths: type: number required: - message - summary: '' + summary: Download an agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/{agentPolicyId}/full: get: - description: Get a full agent policy by ID + description: Get a full agent policy by ID. operationId: get-fleet-agent-policies-agentpolicyid-full parameters: - description: The version of the API to use @@ -14481,12 +14476,12 @@ paths: type: number required: - message - summary: '' + summary: Get a full agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/{agentPolicyId}/outputs: get: - description: Get list of outputs associated with agent policy by policy id + description: Get a list of outputs associated with agent policy by policy id. operationId: get-fleet-agent-policies-agentpolicyid-outputs parameters: - description: The version of the API to use @@ -14585,12 +14580,12 @@ paths: type: number required: - message - summary: '' + summary: Get outputs for an agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/delete: post: - description: Delete agent policy by ID + description: Delete an agent policy by ID. operationId: post-fleet-agent-policies-delete parameters: - description: The version of the API to use @@ -14655,12 +14650,12 @@ paths: type: number required: - message - summary: '' + summary: Delete an agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/outputs: post: - description: Get list of outputs associated with agent policies + description: Get a list of outputs associated with agent policies. operationId: post-fleet-agent-policies-outputs parameters: - description: The version of the API to use @@ -14777,12 +14772,11 @@ paths: type: number required: - message - summary: '' + summary: Get outputs for agent policies tags: - Elastic Agent policies /api/fleet/agent_status: get: - description: Get agent status summary operationId: get-fleet-agent-status parameters: - description: The version of the API to use @@ -14873,12 +14867,11 @@ paths: type: number required: - message - summary: '' + summary: Get an agent status summary tags: - Elastic Agent status /api/fleet/agent_status/data: get: - description: Get incoming agent data operationId: get-fleet-agent-status-data parameters: - description: The version of the API to use @@ -14946,12 +14939,11 @@ paths: type: number required: - message - summary: '' + summary: Get incoming agent data tags: - Elastic Agents /api/fleet/agents: get: - description: List agents operationId: get-fleet-agents parameters: - description: The version of the API to use @@ -15333,11 +15325,10 @@ paths: type: number required: - message - summary: '' + summary: Get agents tags: - Elastic Agents post: - description: List agents by action ids operationId: post-fleet-agents parameters: - description: The version of the API to use @@ -15398,12 +15389,12 @@ paths: type: number required: - message - summary: '' + summary: Get agents by action ids tags: - Elastic Agents /api/fleet/agents/{agentId}: delete: - description: Delete agent by ID + description: Delete an agent by ID. operationId: delete-fleet-agents-agentid parameters: - description: The version of the API to use @@ -15456,11 +15447,11 @@ paths: type: number required: - message - summary: '' + summary: Delete an agent tags: - Elastic Agents get: - description: Get agent by ID + description: Get an agent by ID. operationId: get-fleet-agents-agentid parameters: - description: The version of the API to use @@ -15784,11 +15775,11 @@ paths: type: number required: - message - summary: '' + summary: Get an agent tags: - Elastic Agents put: - description: Update agent by ID + description: Update an agent by ID. operationId: put-fleet-agents-agentid parameters: - description: The version of the API to use @@ -16127,12 +16118,11 @@ paths: type: number required: - message - summary: '' + summary: Update an agent tags: - Elastic Agents /api/fleet/agents/{agentId}/actions: post: - description: Create agent action operationId: post-fleet-agents-agentid-actions parameters: - description: The version of the API to use @@ -16272,12 +16262,11 @@ paths: type: number required: - message - summary: '' + summary: Create an agent action tags: - Elastic Agent actions /api/fleet/agents/{agentId}/reassign: post: - description: Reassign agent operationId: post-fleet-agents-agentid-reassign parameters: - description: The version of the API to use @@ -16335,12 +16324,11 @@ paths: type: number required: - message - summary: '' + summary: Reassign an agent tags: - Elastic Agent actions /api/fleet/agents/{agentId}/request_diagnostics: post: - description: Request agent diagnostics operationId: post-fleet-agents-agentid-request-diagnostics parameters: - description: The version of the API to use @@ -16405,12 +16393,11 @@ paths: type: number required: - message - summary: '' + summary: Request agent diagnostics tags: - Elastic Agent actions /api/fleet/agents/{agentId}/unenroll: post: - description: Unenroll agent operationId: post-fleet-agents-agentid-unenroll parameters: - description: The version of the API to use @@ -16446,12 +16433,11 @@ paths: revoke: type: boolean responses: {} - summary: '' + summary: Unenroll an agent tags: - Elastic Agent actions /api/fleet/agents/{agentId}/upgrade: post: - description: Upgrade agent operationId: post-fleet-agents-agentid-upgrade parameters: - description: The version of the API to use @@ -16515,12 +16501,11 @@ paths: type: number required: - message - summary: '' + summary: Upgrade an agent tags: - Elastic Agent actions /api/fleet/agents/{agentId}/uploads: get: - description: List agent uploads operationId: get-fleet-agents-agentid-uploads parameters: - description: The version of the API to use @@ -16596,12 +16581,11 @@ paths: type: number required: - message - summary: '' + summary: Get agent uploads tags: - Elastic Agents /api/fleet/agents/action_status: get: - description: Get agent action status operationId: get-fleet-agents-action-status parameters: - description: The version of the API to use @@ -16764,12 +16748,11 @@ paths: type: number required: - message - summary: '' + summary: Get an agent action status tags: - Elastic Agent actions /api/fleet/agents/actions/{actionId}/cancel: post: - description: Cancel agent action operationId: post-fleet-agents-actions-actionid-cancel parameters: - description: The version of the API to use @@ -16859,12 +16842,11 @@ paths: type: number required: - message - summary: '' + summary: Cancel an agent action tags: - Elastic Agent actions /api/fleet/agents/available_versions: get: - description: Get available agent versions operationId: get-fleet-agents-available-versions parameters: - description: The version of the API to use @@ -16905,12 +16887,11 @@ paths: type: number required: - message - summary: '' + summary: Get available agent versions tags: - Elastic Agents /api/fleet/agents/bulk_reassign: post: - description: Bulk reassign agents operationId: post-fleet-agents-bulk-reassign parameters: - description: The version of the API to use @@ -16979,12 +16960,11 @@ paths: type: number required: - message - summary: '' + summary: Bulk reassign agents tags: - Elastic Agent actions /api/fleet/agents/bulk_request_diagnostics: post: - description: Bulk request diagnostics from agents operationId: post-fleet-agents-bulk-request-diagnostics parameters: - description: The version of the API to use @@ -17053,12 +17033,11 @@ paths: type: number required: - message - summary: '' + summary: Bulk request diagnostics from agents tags: - Elastic Agent actions /api/fleet/agents/bulk_unenroll: post: - description: Bulk unenroll agents operationId: post-fleet-agents-bulk-unenroll parameters: - description: The version of the API to use @@ -17134,12 +17113,11 @@ paths: type: number required: - message - summary: '' + summary: Bulk unenroll agents tags: - Elastic Agent actions /api/fleet/agents/bulk_update_agent_tags: post: - description: Bulk update agent tags operationId: post-fleet-agents-bulk-update-agent-tags parameters: - description: The version of the API to use @@ -17213,12 +17191,11 @@ paths: type: number required: - message - summary: '' + summary: Bulk update agent tags tags: - Elastic Agent actions /api/fleet/agents/bulk_upgrade: post: - description: Bulk upgrade agents operationId: post-fleet-agents-bulk-upgrade parameters: - description: The version of the API to use @@ -17298,12 +17275,12 @@ paths: type: number required: - message - summary: '' + summary: Bulk upgrade agents tags: - Elastic Agent actions /api/fleet/agents/files/{fileId}: delete: - description: Delete file uploaded by agent + description: Delete a file uploaded by an agent. operationId: delete-fleet-agents-files-fileid parameters: - description: The version of the API to use @@ -17357,12 +17334,12 @@ paths: type: number required: - message - summary: '' + summary: Delete an uploaded file tags: - Elastic Agents /api/fleet/agents/files/{fileId}/{fileName}: get: - description: Get file uploaded by agent + description: Get a file uploaded by an agent. operationId: get-fleet-agents-files-fileid-filename parameters: - description: The version of the API to use @@ -17405,12 +17382,11 @@ paths: type: number required: - message - summary: '' + summary: Get an uploaded file tags: - Elastic Agents /api/fleet/agents/setup: get: - description: Get agent setup info operationId: get-fleet-agents-setup parameters: - description: The version of the API to use @@ -17477,11 +17453,10 @@ paths: type: number required: - message - summary: '' + summary: Get agent setup info tags: - Elastic Agents post: - description: Initiate agent setup operationId: post-fleet-agents-setup parameters: - description: The version of the API to use @@ -17546,12 +17521,11 @@ paths: type: number required: - message - summary: '' + summary: Initiate agent setup tags: - Elastic Agents /api/fleet/agents/tags: get: - description: List agent tags operationId: get-fleet-agents-tags parameters: - description: The version of the API to use @@ -17603,12 +17577,11 @@ paths: type: number required: - message - summary: '' + summary: Get agent tags tags: - Elastic Agents /api/fleet/check-permissions: get: - description: Check permissions operationId: get-fleet-check-permissions parameters: - description: The version of the API to use @@ -17658,12 +17631,11 @@ paths: type: number required: - message - summary: '' + summary: Check permissions tags: - Fleet internals /api/fleet/data_streams: get: - description: List data streams operationId: get-fleet-data-streams parameters: - description: The version of the API to use @@ -17763,12 +17735,11 @@ paths: type: number required: - message - summary: '' + summary: Get data streams tags: - Data streams /api/fleet/enrollment_api_keys: get: - description: List enrollment API keys operationId: get-fleet-enrollment-api-keys parameters: - description: The version of the API to use @@ -17868,11 +17839,10 @@ paths: type: number required: - message - summary: '' + summary: Get enrollment API keys tags: - Fleet enrollment API keys post: - description: Create enrollment API key operationId: post-fleet-enrollment-api-keys parameters: - description: The version of the API to use @@ -17971,12 +17941,12 @@ paths: type: number required: - message - summary: '' + summary: Create an enrollment API key tags: - Fleet enrollment API keys /api/fleet/enrollment_api_keys/{keyId}: delete: - description: Revoke enrollment API key by ID by marking it as inactive + description: Revoke an enrollment API key by ID by marking it as inactive. operationId: delete-fleet-enrollment-api-keys-keyid parameters: - description: The version of the API to use @@ -18029,11 +17999,11 @@ paths: type: number required: - message - summary: '' + summary: Revoke an enrollment API key tags: - Fleet enrollment API keys get: - description: Get enrollment API key by ID + description: Get an enrollment API key by ID. operationId: get-fleet-enrollment-api-keys-keyid parameters: - description: The version of the API to use @@ -18110,12 +18080,11 @@ paths: type: number required: - message - summary: '' + summary: Get an enrollment API key tags: - Fleet enrollment API keys /api/fleet/epm/bulk_assets: post: - description: Bulk get assets operationId: post-fleet-epm-bulk-assets parameters: - description: The version of the API to use @@ -18209,12 +18178,11 @@ paths: type: number required: - message - summary: '' + summary: Bulk get assets tags: - Elastic Package Manager (EPM) /api/fleet/epm/categories: get: - description: List package categories operationId: get-fleet-epm-categories parameters: - description: The version of the API to use @@ -18281,12 +18249,11 @@ paths: type: number required: - message - summary: '' + summary: Get package categories tags: - Elastic Package Manager (EPM) /api/fleet/epm/custom_integrations: post: - description: Create custom integration operationId: post-fleet-epm-custom-integrations parameters: - description: The version of the API to use @@ -18424,12 +18391,11 @@ paths: type: number required: - message - summary: '' + summary: Create a custom integration tags: - Elastic Package Manager (EPM) /api/fleet/epm/data_streams: get: - description: List data streams operationId: get-fleet-epm-data-streams parameters: - description: The version of the API to use @@ -18507,12 +18473,11 @@ paths: type: number required: - message - summary: '' + summary: Get data streams tags: - Data streams /api/fleet/epm/packages: get: - description: List packages operationId: get-fleet-epm-packages parameters: - description: The version of the API to use @@ -18908,11 +18873,10 @@ paths: type: number required: - message - summary: '' + summary: Get packages tags: - Elastic Package Manager (EPM) post: - description: Install package by upload operationId: post-fleet-epm-packages parameters: - description: The version of the API to use @@ -19035,12 +18999,11 @@ paths: type: number required: - message - summary: '' + summary: Install a package by upload tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/_bulk: post: - description: Bulk install packages operationId: post-fleet-epm-packages-bulk parameters: - description: The version of the API to use @@ -19218,12 +19181,11 @@ paths: type: number required: - message - summary: '' + summary: Bulk install packages tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/{pkgName}/{pkgVersion}: delete: - description: Delete package operationId: delete-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use @@ -19334,11 +19296,10 @@ paths: type: number required: - message - summary: '' + summary: Delete a package tags: - Elastic Package Manager (EPM) get: - description: Get package operationId: get-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use @@ -19814,11 +19775,10 @@ paths: type: number required: - message - summary: '' + summary: Get a package tags: - Elastic Package Manager (EPM) post: - description: Install package from registry operationId: post-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use @@ -19964,11 +19924,10 @@ paths: type: number required: - message - summary: '' + summary: Install a package from the registry tags: - Elastic Package Manager (EPM) put: - description: Update package settings operationId: put-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use @@ -20433,12 +20392,11 @@ paths: type: number required: - message - summary: '' + summary: Update package settings tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/{pkgName}/{pkgVersion}/{filePath*}: get: - description: Get package file operationId: get-fleet-epm-packages-pkgname-pkgversion-filepath parameters: - description: The version of the API to use @@ -20485,12 +20443,11 @@ paths: type: number required: - message - summary: '' + summary: Get a package file tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/{pkgName}/{pkgVersion}/transforms/authorize: post: - description: Authorize transforms operationId: post-fleet-epm-packages-pkgname-pkgversion-transforms-authorize parameters: - description: The version of the API to use @@ -20578,12 +20535,11 @@ paths: type: number required: - message - summary: '' + summary: Authorize transforms tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/{pkgName}/stats: get: - description: Get package stats operationId: get-fleet-epm-packages-pkgname-stats parameters: - description: The version of the API to use @@ -20633,12 +20589,11 @@ paths: type: number required: - message - summary: '' + summary: Get package stats tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/installed: get: - description: Get installed packages operationId: get-fleet-epm-packages-installed parameters: - description: The version of the API to use @@ -20787,12 +20742,11 @@ paths: type: number required: - message - summary: '' + summary: Get installed packages tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/limited: get: - description: Get limited package list operationId: get-fleet-epm-packages-limited parameters: - description: The version of the API to use @@ -20833,12 +20787,11 @@ paths: type: number required: - message - summary: '' + summary: Get a limited package list tags: - Elastic Package Manager (EPM) /api/fleet/epm/templates/{pkgName}/{pkgVersion}/inputs: get: - description: Get inputs template operationId: get-fleet-epm-templates-pkgname-pkgversion-inputs parameters: - description: The version of the API to use @@ -20941,12 +20894,11 @@ paths: type: number required: - message - summary: '' + summary: Get an inputs template tags: - Elastic Package Manager (EPM) /api/fleet/epm/verification_key_id: get: - description: Get a package signature verification key ID operationId: get-fleet-epm-verification-key-id parameters: - description: The version of the API to use @@ -20986,12 +20938,11 @@ paths: type: number required: - message - summary: '' + summary: Get a package signature verification key ID tags: - Elastic Package Manager (EPM) /api/fleet/fleet_server_hosts: get: - description: List Fleet Server hosts operationId: get-fleet-fleet-server-hosts parameters: - description: The version of the API to use @@ -21067,11 +21018,10 @@ paths: type: number required: - message - summary: '' + summary: Get Fleet Server hosts tags: - Fleet Server hosts post: - description: Create Fleet Server host operationId: post-fleet-fleet-server-hosts parameters: - description: The version of the API to use @@ -21173,12 +21123,12 @@ paths: type: number required: - message - summary: '' + summary: Create a Fleet Server host tags: - Fleet Server hosts /api/fleet/fleet_server_hosts/{itemId}: delete: - description: Delete Fleet Server host by ID + description: Delete a Fleet Server host by ID. operationId: delete-fleet-fleet-server-hosts-itemid parameters: - description: The version of the API to use @@ -21229,11 +21179,11 @@ paths: type: number required: - message - summary: '' + summary: Delete a Fleet Server host tags: - Fleet Server hosts get: - description: Get Fleet Server host by ID + description: Get a Fleet Server host by ID. operationId: get-fleet-fleet-server-hosts-itemid parameters: - description: The version of the API to use @@ -21303,11 +21253,11 @@ paths: type: number required: - message - summary: '' + summary: Get a Fleet Server host tags: - Fleet Server hosts put: - description: Update Fleet Server host by ID + description: Update a Fleet Server host by ID. operationId: put-fleet-fleet-server-hosts-itemid parameters: - description: The version of the API to use @@ -21407,12 +21357,11 @@ paths: type: number required: - message - summary: '' + summary: Update a Fleet Server host tags: - Fleet Server hosts /api/fleet/health_check: post: - description: Check Fleet Server health operationId: post-fleet-health-check parameters: - description: The version of the API to use @@ -21489,12 +21438,11 @@ paths: type: number required: - message - summary: '' + summary: Check Fleet Server health tags: - Fleet internals /api/fleet/kubernetes: get: - description: Get full K8s agent manifest operationId: get-fleet-kubernetes parameters: - description: The version of the API to use @@ -21548,7 +21496,7 @@ paths: type: number required: - message - summary: '' + summary: Get a full K8s agent manifest tags: - Elastic Agent policies /api/fleet/kubernetes/download: @@ -21616,12 +21564,11 @@ paths: type: number required: - message - summary: '' + summary: Download an agent manifest tags: - Elastic Agent policies /api/fleet/logstash_api_keys: post: - description: Generate Logstash API key operationId: post-fleet-logstash-api-keys parameters: - description: The version of the API to use @@ -21667,12 +21614,11 @@ paths: type: number required: - message - summary: '' + summary: Generate a Logstash API key tags: - Fleet outputs /api/fleet/message_signing_service/rotate_key_pair: post: - description: Rotate fleet message signing key pair operationId: post-fleet-message-signing-service-rotate-key-pair parameters: - description: The version of the API to use @@ -21740,12 +21686,11 @@ paths: type: number required: - message - summary: '' + summary: Rotate a Fleet message signing key pair tags: - Message Signing Service /api/fleet/outputs: get: - description: List outputs operationId: get-fleet-outputs parameters: - description: The version of the API to use @@ -22419,29 +22364,6 @@ paths: type: number topic: type: string - topics: - items: - additionalProperties: true - type: object - properties: - topic: - type: string - when: - additionalProperties: true - type: object - properties: - condition: - type: string - type: - enum: - - equals - - contains - - regexp - type: string - required: - - topic - minItems: 1 - type: array type: enum: - kafka @@ -22497,11 +22419,10 @@ paths: type: number required: - message - summary: '' + summary: Get outputs tags: - Fleet outputs post: - description: Create output operationId: post-fleet-outputs parameters: - description: The version of the API to use @@ -23176,29 +23097,6 @@ paths: type: number topic: type: string - topics: - items: - additionalProperties: false - type: object - properties: - topic: - type: string - when: - additionalProperties: false - type: object - properties: - condition: - type: string - type: - enum: - - equals - - contains - - regexp - type: string - required: - - topic - minItems: 1 - type: array type: enum: - kafka @@ -23888,29 +23786,6 @@ paths: type: number topic: type: string - topics: - items: - additionalProperties: true - type: object - properties: - topic: - type: string - when: - additionalProperties: true - type: object - properties: - condition: - type: string - type: - enum: - - equals - - contains - - regexp - type: string - required: - - topic - minItems: 1 - type: array type: enum: - kafka @@ -23956,12 +23831,12 @@ paths: type: number required: - message - summary: '' + summary: Create output tags: - Fleet outputs /api/fleet/outputs/{outputId}: delete: - description: Delete output by ID + description: Delete output by ID. operationId: delete-fleet-outputs-outputid parameters: - description: The version of the API to use @@ -24028,11 +23903,11 @@ paths: type: number required: - message - summary: '' + summary: Delete output tags: - Fleet outputs get: - description: Get output by ID + description: Get output by ID. operationId: get-fleet-outputs-outputid parameters: - description: The version of the API to use @@ -24710,29 +24585,6 @@ paths: type: number topic: type: string - topics: - items: - additionalProperties: true - type: object - properties: - topic: - type: string - when: - additionalProperties: true - type: object - properties: - condition: - type: string - type: - enum: - - equals - - contains - - regexp - type: string - required: - - topic - minItems: 1 - type: array type: enum: - kafka @@ -24778,11 +24630,11 @@ paths: type: number required: - message - summary: '' + summary: Get output tags: - Fleet outputs put: - description: Update output by ID + description: Update output by ID. operationId: put-fleet-outputs-outputid parameters: - description: The version of the API to use @@ -25444,29 +25296,6 @@ paths: type: number topic: type: string - topics: - items: - additionalProperties: false - type: object - properties: - topic: - type: string - when: - additionalProperties: false - type: object - properties: - condition: - type: string - type: - enum: - - equals - - contains - - regexp - type: string - required: - - topic - minItems: 1 - type: array type: enum: - kafka @@ -26153,29 +25982,6 @@ paths: type: number topic: type: string - topics: - items: - additionalProperties: true - type: object - properties: - topic: - type: string - when: - additionalProperties: true - type: object - properties: - condition: - type: string - type: - enum: - - equals - - contains - - regexp - type: string - required: - - topic - minItems: 1 - type: array type: enum: - kafka @@ -26221,12 +26027,11 @@ paths: type: number required: - message - summary: '' + summary: Update output tags: - Fleet outputs /api/fleet/outputs/{outputId}/health: get: - description: Get latest output health operationId: get-fleet-outputs-outputid-health parameters: - description: The version of the API to use @@ -26279,12 +26084,11 @@ paths: type: number required: - message - summary: '' + summary: Get the latest output health tags: - Fleet outputs /api/fleet/package_policies: get: - description: List package policies operationId: get-fleet-package-policies parameters: - description: The version of the API to use @@ -26785,11 +26589,10 @@ paths: type: number required: - message - summary: '' + summary: Get package policies tags: - Fleet package policies post: - description: Create package policy operationId: post-fleet-package-policies parameters: - description: The version of the API to use @@ -27687,12 +27490,11 @@ paths: type: number required: - message - summary: '' + summary: Create a package policy tags: - Fleet package policies /api/fleet/package_policies/_bulk_get: post: - description: Bulk get package policies operationId: post-fleet-package-policies-bulk-get parameters: - description: The version of the API to use @@ -28180,12 +27982,12 @@ paths: type: string required: - message - summary: '' + summary: Bulk get package policies tags: - Fleet package policies /api/fleet/package_policies/{packagePolicyId}: delete: - description: Delete package policy by ID + description: Delete a package policy by ID. operationId: delete-fleet-package-policies-packagepolicyid parameters: - description: The version of the API to use @@ -28241,11 +28043,11 @@ paths: type: number required: - message - summary: '' + summary: Delete a package policy tags: - Fleet package policies get: - description: Get package policy by ID + description: Get a package policy by ID. operationId: get-fleet-package-policies-packagepolicyid parameters: - description: The version of the API to use @@ -28710,11 +28512,11 @@ paths: type: string required: - message - summary: '' + summary: Get a package policy tags: - Fleet package policies put: - description: Update package policy by ID + description: Update a package policy by ID. operationId: put-fleet-package-policies-packagepolicyid parameters: - description: The version of the API to use @@ -29606,12 +29408,11 @@ paths: type: number required: - message - summary: '' + summary: Update a package policy tags: - Fleet package policies /api/fleet/package_policies/delete: post: - description: Bulk delete package policies operationId: post-fleet-package-policies-delete parameters: - description: The version of the API to use @@ -29743,12 +29544,12 @@ paths: type: number required: - message - summary: '' + summary: Bulk delete package policies tags: - Fleet package policies /api/fleet/package_policies/upgrade: post: - description: Upgrade package policy to a newer package version + description: Upgrade a package policy to a newer package version. operationId: post-fleet-package-policies-upgrade parameters: - description: The version of the API to use @@ -29824,12 +29625,11 @@ paths: type: number required: - message - summary: '' + summary: Upgrade a package policy tags: - Fleet package policies /api/fleet/package_policies/upgrade/dryrun: post: - description: Dry run package policy upgrade operationId: post-fleet-package-policies-upgrade-dryrun parameters: - description: The version of the API to use @@ -30674,12 +30474,11 @@ paths: type: number required: - message - summary: '' + summary: Dry run a package policy upgrade tags: - Fleet package policies /api/fleet/proxies: get: - description: List proxies operationId: get-fleet-proxies parameters: - description: The version of the API to use @@ -30761,11 +30560,10 @@ paths: type: number required: - message - summary: '' + summary: Get proxies tags: - Fleet proxies post: - description: Create proxy operationId: post-fleet-proxies parameters: - description: The version of the API to use @@ -30879,12 +30677,12 @@ paths: type: number required: - message - summary: '' + summary: Create a proxy tags: - Fleet proxies /api/fleet/proxies/{itemId}: delete: - description: Delete proxy by ID + description: Delete a proxy by ID operationId: delete-fleet-proxies-itemid parameters: - description: The version of the API to use @@ -30935,11 +30733,11 @@ paths: type: number required: - message - summary: '' + summary: Delete a proxy tags: - Fleet proxies get: - description: Get proxy by ID + description: Get a proxy by ID. operationId: get-fleet-proxies-itemid parameters: - description: The version of the API to use @@ -31015,11 +30813,11 @@ paths: type: number required: - message - summary: '' + summary: Get a proxy tags: - Fleet proxies put: - description: Update proxy by ID + description: Update a proxy by ID. operationId: put-fleet-proxies-itemid parameters: - description: The version of the API to use @@ -31135,12 +30933,11 @@ paths: type: number required: - message - summary: '' + summary: Update a proxy tags: - Fleet proxies /api/fleet/service_tokens: post: - description: Create a service token operationId: post-fleet-service-tokens parameters: - description: The version of the API to use @@ -31200,12 +30997,11 @@ paths: type: number required: - message - summary: '' + summary: Create a service token tags: - Fleet service tokens /api/fleet/settings: get: - description: Get settings operationId: get-fleet-settings parameters: - description: The version of the API to use @@ -31296,11 +31092,10 @@ paths: type: string required: - message - summary: '' + summary: Get settings tags: - Fleet internals put: - description: Update settings operationId: put-fleet-settings parameters: - description: The version of the API to use @@ -31429,12 +31224,11 @@ paths: type: string required: - message - summary: '' + summary: Update settings tags: - Fleet internals /api/fleet/setup: post: - description: Initiate Fleet setup operationId: post-fleet-setup parameters: - description: The version of the API to use @@ -31511,12 +31305,12 @@ paths: type: string required: - message - summary: '' + summary: Initiate Fleet setup tags: - Fleet internals /api/fleet/uninstall_tokens: get: - description: List metadata for latest uninstall tokens per agent policy + description: List the metadata for the latest uninstall tokens per agent policy. operationId: get-fleet-uninstall-tokens parameters: - description: The version of the API to use @@ -31611,12 +31405,12 @@ paths: type: number required: - message - summary: '' + summary: Get metadata for latest uninstall tokens tags: - Fleet uninstall tokens /api/fleet/uninstall_tokens/{uninstallTokenId}: get: - description: Get one decrypted uninstall token by its ID + description: Get one decrypted uninstall token by its ID. operationId: get-fleet-uninstall-tokens-uninstalltokenid parameters: - description: The version of the API to use @@ -31682,7 +31476,7 @@ paths: type: number required: - message - summary: '' + summary: Get a decrypted uninstall token tags: - Fleet uninstall tokens /api/lists: @@ -50524,7 +50318,7 @@ tags: name: ml - name: roles - description: > - Export sets of saved objects that you want to import into {kib}, resolve + Export sets of saved objects that you want to import into Kibana, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs. diff --git a/oas_docs/output/kibana.staging.yaml b/oas_docs/output/kibana.staging.yaml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index 64d227b91979..133dede5fcd0 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -13303,7 +13303,6 @@ paths: - Security Exceptions API /api/fleet/agent_download_sources: get: - description: List agent binary download sources operationId: get-fleet-agent-download-sources parameters: - description: The version of the API to use @@ -13375,11 +13374,10 @@ paths: type: number required: - message - summary: '' + summary: Get agent binary download sources tags: - Elastic Agent binary download sources post: - description: Create agent binary download source operationId: post-fleet-agent-download-sources parameters: - description: The version of the API to use @@ -13473,12 +13471,12 @@ paths: type: number required: - message - summary: '' + summary: Create an agent binary download source tags: - Elastic Agent binary download sources /api/fleet/agent_download_sources/{sourceId}: delete: - description: Delete agent binary download source by ID + description: Delete an agent binary download source by ID. operationId: delete-fleet-agent-download-sources-sourceid parameters: - description: The version of the API to use @@ -13529,11 +13527,11 @@ paths: type: number required: - message - summary: '' + summary: Delete an agent binary download source tags: - Elastic Agent binary download sources get: - description: Get agent binary download source by ID + description: Get an agent binary download source by ID. operationId: get-fleet-agent-download-sources-sourceid parameters: - description: The version of the API to use @@ -13599,11 +13597,11 @@ paths: type: number required: - message - summary: '' + summary: Get an agent binary download source tags: - Elastic Agent binary download sources put: - description: Update agent binary download source by ID + description: Update an agent binary download source by ID. operationId: put-fleet-agent-download-sources-sourceid parameters: - description: The version of the API to use @@ -13702,12 +13700,11 @@ paths: type: number required: - message - summary: '' + summary: Update an agent binary download source tags: - Elastic Agent binary download sources /api/fleet/agent_policies: get: - description: List agent policies operationId: get-fleet-agent-policies parameters: - description: The version of the API to use @@ -14317,11 +14314,10 @@ paths: type: number required: - message - summary: '' + summary: Get agent policies tags: - Elastic Agent policies post: - description: Create an agent policy operationId: post-fleet-agent-policies parameters: - description: The version of the API to use @@ -15051,12 +15047,11 @@ paths: type: number required: - message - summary: '' + summary: Create an agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/_bulk_get: post: - description: Bulk get agent policies operationId: post-fleet-agent-policies-bulk-get parameters: - description: The version of the API to use @@ -15631,12 +15626,12 @@ paths: type: number required: - message - summary: '' + summary: Bulk get agent policies tags: - Elastic Agent policies /api/fleet/agent_policies/{agentPolicyId}: get: - description: Get an agent policy by ID + description: Get an agent policy by ID. operationId: get-fleet-agent-policies-agentpolicyid parameters: - description: The version of the API to use @@ -16188,11 +16183,11 @@ paths: type: number required: - message - summary: '' + summary: Get an agent policy tags: - Elastic Agent policies put: - description: Update an agent policy by ID + description: Update an agent policy by ID. operationId: put-fleet-agent-policies-agentpolicyid parameters: - description: The version of the API to use @@ -16930,12 +16925,12 @@ paths: type: number required: - message - summary: '' + summary: Update an agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/{agentPolicyId}/copy: post: - description: Copy an agent policy by ID + description: Copy an agent policy by ID. operationId: post-fleet-agent-policies-agentpolicyid-copy parameters: - description: The version of the API to use @@ -17508,12 +17503,12 @@ paths: type: number required: - message - summary: '' + summary: Copy an agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/{agentPolicyId}/download: get: - description: Download an agent policy by ID + description: Download an agent policy by ID. operationId: get-fleet-agent-policies-agentpolicyid-download parameters: - description: The version of the API to use @@ -17582,12 +17577,12 @@ paths: type: number required: - message - summary: '' + summary: Download an agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/{agentPolicyId}/full: get: - description: Get a full agent policy by ID + description: Get a full agent policy by ID. operationId: get-fleet-agent-policies-agentpolicyid-full parameters: - description: The version of the API to use @@ -17914,12 +17909,12 @@ paths: type: number required: - message - summary: '' + summary: Get a full agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/{agentPolicyId}/outputs: get: - description: Get list of outputs associated with agent policy by policy id + description: Get a list of outputs associated with agent policy by policy id. operationId: get-fleet-agent-policies-agentpolicyid-outputs parameters: - description: The version of the API to use @@ -18018,12 +18013,12 @@ paths: type: number required: - message - summary: '' + summary: Get outputs for an agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/delete: post: - description: Delete agent policy by ID + description: Delete an agent policy by ID. operationId: post-fleet-agent-policies-delete parameters: - description: The version of the API to use @@ -18088,12 +18083,12 @@ paths: type: number required: - message - summary: '' + summary: Delete an agent policy tags: - Elastic Agent policies /api/fleet/agent_policies/outputs: post: - description: Get list of outputs associated with agent policies + description: Get a list of outputs associated with agent policies. operationId: post-fleet-agent-policies-outputs parameters: - description: The version of the API to use @@ -18210,12 +18205,11 @@ paths: type: number required: - message - summary: '' + summary: Get outputs for agent policies tags: - Elastic Agent policies /api/fleet/agent_status: get: - description: Get agent status summary operationId: get-fleet-agent-status parameters: - description: The version of the API to use @@ -18306,12 +18300,11 @@ paths: type: number required: - message - summary: '' + summary: Get an agent status summary tags: - Elastic Agent status /api/fleet/agent_status/data: get: - description: Get incoming agent data operationId: get-fleet-agent-status-data parameters: - description: The version of the API to use @@ -18379,12 +18372,11 @@ paths: type: number required: - message - summary: '' + summary: Get incoming agent data tags: - Elastic Agents /api/fleet/agents: get: - description: List agents operationId: get-fleet-agents parameters: - description: The version of the API to use @@ -18766,11 +18758,10 @@ paths: type: number required: - message - summary: '' + summary: Get agents tags: - Elastic Agents post: - description: List agents by action ids operationId: post-fleet-agents parameters: - description: The version of the API to use @@ -18831,12 +18822,12 @@ paths: type: number required: - message - summary: '' + summary: Get agents by action ids tags: - Elastic Agents /api/fleet/agents/{agentId}: delete: - description: Delete agent by ID + description: Delete an agent by ID. operationId: delete-fleet-agents-agentid parameters: - description: The version of the API to use @@ -18889,11 +18880,11 @@ paths: type: number required: - message - summary: '' + summary: Delete an agent tags: - Elastic Agents get: - description: Get agent by ID + description: Get an agent by ID. operationId: get-fleet-agents-agentid parameters: - description: The version of the API to use @@ -19217,11 +19208,11 @@ paths: type: number required: - message - summary: '' + summary: Get an agent tags: - Elastic Agents put: - description: Update agent by ID + description: Update an agent by ID. operationId: put-fleet-agents-agentid parameters: - description: The version of the API to use @@ -19560,12 +19551,11 @@ paths: type: number required: - message - summary: '' + summary: Update an agent tags: - Elastic Agents /api/fleet/agents/{agentId}/actions: post: - description: Create agent action operationId: post-fleet-agents-agentid-actions parameters: - description: The version of the API to use @@ -19705,12 +19695,11 @@ paths: type: number required: - message - summary: '' + summary: Create an agent action tags: - Elastic Agent actions /api/fleet/agents/{agentId}/reassign: post: - description: Reassign agent operationId: post-fleet-agents-agentid-reassign parameters: - description: The version of the API to use @@ -19768,12 +19757,11 @@ paths: type: number required: - message - summary: '' + summary: Reassign an agent tags: - Elastic Agent actions /api/fleet/agents/{agentId}/request_diagnostics: post: - description: Request agent diagnostics operationId: post-fleet-agents-agentid-request-diagnostics parameters: - description: The version of the API to use @@ -19838,12 +19826,11 @@ paths: type: number required: - message - summary: '' + summary: Request agent diagnostics tags: - Elastic Agent actions /api/fleet/agents/{agentId}/unenroll: post: - description: Unenroll agent operationId: post-fleet-agents-agentid-unenroll parameters: - description: The version of the API to use @@ -19879,12 +19866,11 @@ paths: revoke: type: boolean responses: {} - summary: '' + summary: Unenroll an agent tags: - Elastic Agent actions /api/fleet/agents/{agentId}/upgrade: post: - description: Upgrade agent operationId: post-fleet-agents-agentid-upgrade parameters: - description: The version of the API to use @@ -19948,12 +19934,11 @@ paths: type: number required: - message - summary: '' + summary: Upgrade an agent tags: - Elastic Agent actions /api/fleet/agents/{agentId}/uploads: get: - description: List agent uploads operationId: get-fleet-agents-agentid-uploads parameters: - description: The version of the API to use @@ -20029,12 +20014,11 @@ paths: type: number required: - message - summary: '' + summary: Get agent uploads tags: - Elastic Agents /api/fleet/agents/action_status: get: - description: Get agent action status operationId: get-fleet-agents-action-status parameters: - description: The version of the API to use @@ -20197,12 +20181,11 @@ paths: type: number required: - message - summary: '' + summary: Get an agent action status tags: - Elastic Agent actions /api/fleet/agents/actions/{actionId}/cancel: post: - description: Cancel agent action operationId: post-fleet-agents-actions-actionid-cancel parameters: - description: The version of the API to use @@ -20292,12 +20275,11 @@ paths: type: number required: - message - summary: '' + summary: Cancel an agent action tags: - Elastic Agent actions /api/fleet/agents/available_versions: get: - description: Get available agent versions operationId: get-fleet-agents-available-versions parameters: - description: The version of the API to use @@ -20338,12 +20320,11 @@ paths: type: number required: - message - summary: '' + summary: Get available agent versions tags: - Elastic Agents /api/fleet/agents/bulk_reassign: post: - description: Bulk reassign agents operationId: post-fleet-agents-bulk-reassign parameters: - description: The version of the API to use @@ -20412,12 +20393,11 @@ paths: type: number required: - message - summary: '' + summary: Bulk reassign agents tags: - Elastic Agent actions /api/fleet/agents/bulk_request_diagnostics: post: - description: Bulk request diagnostics from agents operationId: post-fleet-agents-bulk-request-diagnostics parameters: - description: The version of the API to use @@ -20486,12 +20466,11 @@ paths: type: number required: - message - summary: '' + summary: Bulk request diagnostics from agents tags: - Elastic Agent actions /api/fleet/agents/bulk_unenroll: post: - description: Bulk unenroll agents operationId: post-fleet-agents-bulk-unenroll parameters: - description: The version of the API to use @@ -20567,12 +20546,11 @@ paths: type: number required: - message - summary: '' + summary: Bulk unenroll agents tags: - Elastic Agent actions /api/fleet/agents/bulk_update_agent_tags: post: - description: Bulk update agent tags operationId: post-fleet-agents-bulk-update-agent-tags parameters: - description: The version of the API to use @@ -20646,12 +20624,11 @@ paths: type: number required: - message - summary: '' + summary: Bulk update agent tags tags: - Elastic Agent actions /api/fleet/agents/bulk_upgrade: post: - description: Bulk upgrade agents operationId: post-fleet-agents-bulk-upgrade parameters: - description: The version of the API to use @@ -20731,12 +20708,12 @@ paths: type: number required: - message - summary: '' + summary: Bulk upgrade agents tags: - Elastic Agent actions /api/fleet/agents/files/{fileId}: delete: - description: Delete file uploaded by agent + description: Delete a file uploaded by an agent. operationId: delete-fleet-agents-files-fileid parameters: - description: The version of the API to use @@ -20790,12 +20767,12 @@ paths: type: number required: - message - summary: '' + summary: Delete an uploaded file tags: - Elastic Agents /api/fleet/agents/files/{fileId}/{fileName}: get: - description: Get file uploaded by agent + description: Get a file uploaded by an agent. operationId: get-fleet-agents-files-fileid-filename parameters: - description: The version of the API to use @@ -20838,12 +20815,11 @@ paths: type: number required: - message - summary: '' + summary: Get an uploaded file tags: - Elastic Agents /api/fleet/agents/setup: get: - description: Get agent setup info operationId: get-fleet-agents-setup parameters: - description: The version of the API to use @@ -20910,11 +20886,10 @@ paths: type: number required: - message - summary: '' + summary: Get agent setup info tags: - Elastic Agents post: - description: Initiate agent setup operationId: post-fleet-agents-setup parameters: - description: The version of the API to use @@ -20979,12 +20954,11 @@ paths: type: number required: - message - summary: '' + summary: Initiate agent setup tags: - Elastic Agents /api/fleet/agents/tags: get: - description: List agent tags operationId: get-fleet-agents-tags parameters: - description: The version of the API to use @@ -21036,12 +21010,11 @@ paths: type: number required: - message - summary: '' + summary: Get agent tags tags: - Elastic Agents /api/fleet/check-permissions: get: - description: Check permissions operationId: get-fleet-check-permissions parameters: - description: The version of the API to use @@ -21091,12 +21064,11 @@ paths: type: number required: - message - summary: '' + summary: Check permissions tags: - Fleet internals /api/fleet/data_streams: get: - description: List data streams operationId: get-fleet-data-streams parameters: - description: The version of the API to use @@ -21196,12 +21168,11 @@ paths: type: number required: - message - summary: '' + summary: Get data streams tags: - Data streams /api/fleet/enrollment_api_keys: get: - description: List enrollment API keys operationId: get-fleet-enrollment-api-keys parameters: - description: The version of the API to use @@ -21301,11 +21272,10 @@ paths: type: number required: - message - summary: '' + summary: Get enrollment API keys tags: - Fleet enrollment API keys post: - description: Create enrollment API key operationId: post-fleet-enrollment-api-keys parameters: - description: The version of the API to use @@ -21404,12 +21374,12 @@ paths: type: number required: - message - summary: '' + summary: Create an enrollment API key tags: - Fleet enrollment API keys /api/fleet/enrollment_api_keys/{keyId}: delete: - description: Revoke enrollment API key by ID by marking it as inactive + description: Revoke an enrollment API key by ID by marking it as inactive. operationId: delete-fleet-enrollment-api-keys-keyid parameters: - description: The version of the API to use @@ -21462,11 +21432,11 @@ paths: type: number required: - message - summary: '' + summary: Revoke an enrollment API key tags: - Fleet enrollment API keys get: - description: Get enrollment API key by ID + description: Get an enrollment API key by ID. operationId: get-fleet-enrollment-api-keys-keyid parameters: - description: The version of the API to use @@ -21543,12 +21513,11 @@ paths: type: number required: - message - summary: '' + summary: Get an enrollment API key tags: - Fleet enrollment API keys /api/fleet/epm/bulk_assets: post: - description: Bulk get assets operationId: post-fleet-epm-bulk-assets parameters: - description: The version of the API to use @@ -21642,12 +21611,11 @@ paths: type: number required: - message - summary: '' + summary: Bulk get assets tags: - Elastic Package Manager (EPM) /api/fleet/epm/categories: get: - description: List package categories operationId: get-fleet-epm-categories parameters: - description: The version of the API to use @@ -21714,12 +21682,11 @@ paths: type: number required: - message - summary: '' + summary: Get package categories tags: - Elastic Package Manager (EPM) /api/fleet/epm/custom_integrations: post: - description: Create custom integration operationId: post-fleet-epm-custom-integrations parameters: - description: The version of the API to use @@ -21857,12 +21824,11 @@ paths: type: number required: - message - summary: '' + summary: Create a custom integration tags: - Elastic Package Manager (EPM) /api/fleet/epm/data_streams: get: - description: List data streams operationId: get-fleet-epm-data-streams parameters: - description: The version of the API to use @@ -21940,12 +21906,11 @@ paths: type: number required: - message - summary: '' + summary: Get data streams tags: - Data streams /api/fleet/epm/packages: get: - description: List packages operationId: get-fleet-epm-packages parameters: - description: The version of the API to use @@ -22341,11 +22306,10 @@ paths: type: number required: - message - summary: '' + summary: Get packages tags: - Elastic Package Manager (EPM) post: - description: Install package by upload operationId: post-fleet-epm-packages parameters: - description: The version of the API to use @@ -22468,12 +22432,11 @@ paths: type: number required: - message - summary: '' + summary: Install a package by upload tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/_bulk: post: - description: Bulk install packages operationId: post-fleet-epm-packages-bulk parameters: - description: The version of the API to use @@ -22651,12 +22614,11 @@ paths: type: number required: - message - summary: '' + summary: Bulk install packages tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/{pkgName}/{pkgVersion}: delete: - description: Delete package operationId: delete-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use @@ -22767,11 +22729,10 @@ paths: type: number required: - message - summary: '' + summary: Delete a package tags: - Elastic Package Manager (EPM) get: - description: Get package operationId: get-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use @@ -23247,11 +23208,10 @@ paths: type: number required: - message - summary: '' + summary: Get a package tags: - Elastic Package Manager (EPM) post: - description: Install package from registry operationId: post-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use @@ -23397,11 +23357,10 @@ paths: type: number required: - message - summary: '' + summary: Install a package from the registry tags: - Elastic Package Manager (EPM) put: - description: Update package settings operationId: put-fleet-epm-packages-pkgname-pkgversion parameters: - description: The version of the API to use @@ -23866,12 +23825,11 @@ paths: type: number required: - message - summary: '' + summary: Update package settings tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/{pkgName}/{pkgVersion}/{filePath*}: get: - description: Get package file operationId: get-fleet-epm-packages-pkgname-pkgversion-filepath parameters: - description: The version of the API to use @@ -23918,12 +23876,11 @@ paths: type: number required: - message - summary: '' + summary: Get a package file tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/{pkgName}/{pkgVersion}/transforms/authorize: post: - description: Authorize transforms operationId: post-fleet-epm-packages-pkgname-pkgversion-transforms-authorize parameters: - description: The version of the API to use @@ -24011,12 +23968,11 @@ paths: type: number required: - message - summary: '' + summary: Authorize transforms tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/{pkgName}/stats: get: - description: Get package stats operationId: get-fleet-epm-packages-pkgname-stats parameters: - description: The version of the API to use @@ -24066,12 +24022,11 @@ paths: type: number required: - message - summary: '' + summary: Get package stats tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/installed: get: - description: Get installed packages operationId: get-fleet-epm-packages-installed parameters: - description: The version of the API to use @@ -24220,12 +24175,11 @@ paths: type: number required: - message - summary: '' + summary: Get installed packages tags: - Elastic Package Manager (EPM) /api/fleet/epm/packages/limited: get: - description: Get limited package list operationId: get-fleet-epm-packages-limited parameters: - description: The version of the API to use @@ -24266,12 +24220,11 @@ paths: type: number required: - message - summary: '' + summary: Get a limited package list tags: - Elastic Package Manager (EPM) /api/fleet/epm/templates/{pkgName}/{pkgVersion}/inputs: get: - description: Get inputs template operationId: get-fleet-epm-templates-pkgname-pkgversion-inputs parameters: - description: The version of the API to use @@ -24374,12 +24327,11 @@ paths: type: number required: - message - summary: '' + summary: Get an inputs template tags: - Elastic Package Manager (EPM) /api/fleet/epm/verification_key_id: get: - description: Get a package signature verification key ID operationId: get-fleet-epm-verification-key-id parameters: - description: The version of the API to use @@ -24419,12 +24371,11 @@ paths: type: number required: - message - summary: '' + summary: Get a package signature verification key ID tags: - Elastic Package Manager (EPM) /api/fleet/fleet_server_hosts: get: - description: List Fleet Server hosts operationId: get-fleet-fleet-server-hosts parameters: - description: The version of the API to use @@ -24500,11 +24451,10 @@ paths: type: number required: - message - summary: '' + summary: Get Fleet Server hosts tags: - Fleet Server hosts post: - description: Create Fleet Server host operationId: post-fleet-fleet-server-hosts parameters: - description: The version of the API to use @@ -24606,12 +24556,12 @@ paths: type: number required: - message - summary: '' + summary: Create a Fleet Server host tags: - Fleet Server hosts /api/fleet/fleet_server_hosts/{itemId}: delete: - description: Delete Fleet Server host by ID + description: Delete a Fleet Server host by ID. operationId: delete-fleet-fleet-server-hosts-itemid parameters: - description: The version of the API to use @@ -24662,11 +24612,11 @@ paths: type: number required: - message - summary: '' + summary: Delete a Fleet Server host tags: - Fleet Server hosts get: - description: Get Fleet Server host by ID + description: Get a Fleet Server host by ID. operationId: get-fleet-fleet-server-hosts-itemid parameters: - description: The version of the API to use @@ -24736,11 +24686,11 @@ paths: type: number required: - message - summary: '' + summary: Get a Fleet Server host tags: - Fleet Server hosts put: - description: Update Fleet Server host by ID + description: Update a Fleet Server host by ID. operationId: put-fleet-fleet-server-hosts-itemid parameters: - description: The version of the API to use @@ -24840,12 +24790,11 @@ paths: type: number required: - message - summary: '' + summary: Update a Fleet Server host tags: - Fleet Server hosts /api/fleet/health_check: post: - description: Check Fleet Server health operationId: post-fleet-health-check parameters: - description: The version of the API to use @@ -24922,12 +24871,11 @@ paths: type: number required: - message - summary: '' + summary: Check Fleet Server health tags: - Fleet internals /api/fleet/kubernetes: get: - description: Get full K8s agent manifest operationId: get-fleet-kubernetes parameters: - description: The version of the API to use @@ -24981,7 +24929,7 @@ paths: type: number required: - message - summary: '' + summary: Get a full K8s agent manifest tags: - Elastic Agent policies /api/fleet/kubernetes/download: @@ -25049,12 +24997,11 @@ paths: type: number required: - message - summary: '' + summary: Download an agent manifest tags: - Elastic Agent policies /api/fleet/logstash_api_keys: post: - description: Generate Logstash API key operationId: post-fleet-logstash-api-keys parameters: - description: The version of the API to use @@ -25100,12 +25047,11 @@ paths: type: number required: - message - summary: '' + summary: Generate a Logstash API key tags: - Fleet outputs /api/fleet/message_signing_service/rotate_key_pair: post: - description: Rotate fleet message signing key pair operationId: post-fleet-message-signing-service-rotate-key-pair parameters: - description: The version of the API to use @@ -25173,12 +25119,11 @@ paths: type: number required: - message - summary: '' + summary: Rotate a Fleet message signing key pair tags: - Message Signing Service /api/fleet/outputs: get: - description: List outputs operationId: get-fleet-outputs parameters: - description: The version of the API to use @@ -25852,29 +25797,6 @@ paths: type: number topic: type: string - topics: - items: - additionalProperties: true - type: object - properties: - topic: - type: string - when: - additionalProperties: true - type: object - properties: - condition: - type: string - type: - enum: - - equals - - contains - - regexp - type: string - required: - - topic - minItems: 1 - type: array type: enum: - kafka @@ -25930,11 +25852,10 @@ paths: type: number required: - message - summary: '' + summary: Get outputs tags: - Fleet outputs post: - description: Create output operationId: post-fleet-outputs parameters: - description: The version of the API to use @@ -26609,29 +26530,6 @@ paths: type: number topic: type: string - topics: - items: - additionalProperties: false - type: object - properties: - topic: - type: string - when: - additionalProperties: false - type: object - properties: - condition: - type: string - type: - enum: - - equals - - contains - - regexp - type: string - required: - - topic - minItems: 1 - type: array type: enum: - kafka @@ -27321,29 +27219,6 @@ paths: type: number topic: type: string - topics: - items: - additionalProperties: true - type: object - properties: - topic: - type: string - when: - additionalProperties: true - type: object - properties: - condition: - type: string - type: - enum: - - equals - - contains - - regexp - type: string - required: - - topic - minItems: 1 - type: array type: enum: - kafka @@ -27389,12 +27264,12 @@ paths: type: number required: - message - summary: '' + summary: Create output tags: - Fleet outputs /api/fleet/outputs/{outputId}: delete: - description: Delete output by ID + description: Delete output by ID. operationId: delete-fleet-outputs-outputid parameters: - description: The version of the API to use @@ -27461,11 +27336,11 @@ paths: type: number required: - message - summary: '' + summary: Delete output tags: - Fleet outputs get: - description: Get output by ID + description: Get output by ID. operationId: get-fleet-outputs-outputid parameters: - description: The version of the API to use @@ -28143,29 +28018,6 @@ paths: type: number topic: type: string - topics: - items: - additionalProperties: true - type: object - properties: - topic: - type: string - when: - additionalProperties: true - type: object - properties: - condition: - type: string - type: - enum: - - equals - - contains - - regexp - type: string - required: - - topic - minItems: 1 - type: array type: enum: - kafka @@ -28211,11 +28063,11 @@ paths: type: number required: - message - summary: '' + summary: Get output tags: - Fleet outputs put: - description: Update output by ID + description: Update output by ID. operationId: put-fleet-outputs-outputid parameters: - description: The version of the API to use @@ -28877,29 +28729,6 @@ paths: type: number topic: type: string - topics: - items: - additionalProperties: false - type: object - properties: - topic: - type: string - when: - additionalProperties: false - type: object - properties: - condition: - type: string - type: - enum: - - equals - - contains - - regexp - type: string - required: - - topic - minItems: 1 - type: array type: enum: - kafka @@ -29586,29 +29415,6 @@ paths: type: number topic: type: string - topics: - items: - additionalProperties: true - type: object - properties: - topic: - type: string - when: - additionalProperties: true - type: object - properties: - condition: - type: string - type: - enum: - - equals - - contains - - regexp - type: string - required: - - topic - minItems: 1 - type: array type: enum: - kafka @@ -29654,12 +29460,11 @@ paths: type: number required: - message - summary: '' + summary: Update output tags: - Fleet outputs /api/fleet/outputs/{outputId}/health: get: - description: Get latest output health operationId: get-fleet-outputs-outputid-health parameters: - description: The version of the API to use @@ -29712,12 +29517,11 @@ paths: type: number required: - message - summary: '' + summary: Get the latest output health tags: - Fleet outputs /api/fleet/package_policies: get: - description: List package policies operationId: get-fleet-package-policies parameters: - description: The version of the API to use @@ -30218,11 +30022,10 @@ paths: type: number required: - message - summary: '' + summary: Get package policies tags: - Fleet package policies post: - description: Create package policy operationId: post-fleet-package-policies parameters: - description: The version of the API to use @@ -31120,12 +30923,11 @@ paths: type: number required: - message - summary: '' + summary: Create a package policy tags: - Fleet package policies /api/fleet/package_policies/_bulk_get: post: - description: Bulk get package policies operationId: post-fleet-package-policies-bulk-get parameters: - description: The version of the API to use @@ -31613,12 +31415,12 @@ paths: type: string required: - message - summary: '' + summary: Bulk get package policies tags: - Fleet package policies /api/fleet/package_policies/{packagePolicyId}: delete: - description: Delete package policy by ID + description: Delete a package policy by ID. operationId: delete-fleet-package-policies-packagepolicyid parameters: - description: The version of the API to use @@ -31674,11 +31476,11 @@ paths: type: number required: - message - summary: '' + summary: Delete a package policy tags: - Fleet package policies get: - description: Get package policy by ID + description: Get a package policy by ID. operationId: get-fleet-package-policies-packagepolicyid parameters: - description: The version of the API to use @@ -32143,11 +31945,11 @@ paths: type: string required: - message - summary: '' + summary: Get a package policy tags: - Fleet package policies put: - description: Update package policy by ID + description: Update a package policy by ID. operationId: put-fleet-package-policies-packagepolicyid parameters: - description: The version of the API to use @@ -33039,12 +32841,11 @@ paths: type: number required: - message - summary: '' + summary: Update a package policy tags: - Fleet package policies /api/fleet/package_policies/delete: post: - description: Bulk delete package policies operationId: post-fleet-package-policies-delete parameters: - description: The version of the API to use @@ -33176,12 +32977,12 @@ paths: type: number required: - message - summary: '' + summary: Bulk delete package policies tags: - Fleet package policies /api/fleet/package_policies/upgrade: post: - description: Upgrade package policy to a newer package version + description: Upgrade a package policy to a newer package version. operationId: post-fleet-package-policies-upgrade parameters: - description: The version of the API to use @@ -33257,12 +33058,11 @@ paths: type: number required: - message - summary: '' + summary: Upgrade a package policy tags: - Fleet package policies /api/fleet/package_policies/upgrade/dryrun: post: - description: Dry run package policy upgrade operationId: post-fleet-package-policies-upgrade-dryrun parameters: - description: The version of the API to use @@ -34107,12 +33907,11 @@ paths: type: number required: - message - summary: '' + summary: Dry run a package policy upgrade tags: - Fleet package policies /api/fleet/proxies: get: - description: List proxies operationId: get-fleet-proxies parameters: - description: The version of the API to use @@ -34194,11 +33993,10 @@ paths: type: number required: - message - summary: '' + summary: Get proxies tags: - Fleet proxies post: - description: Create proxy operationId: post-fleet-proxies parameters: - description: The version of the API to use @@ -34312,12 +34110,12 @@ paths: type: number required: - message - summary: '' + summary: Create a proxy tags: - Fleet proxies /api/fleet/proxies/{itemId}: delete: - description: Delete proxy by ID + description: Delete a proxy by ID operationId: delete-fleet-proxies-itemid parameters: - description: The version of the API to use @@ -34368,11 +34166,11 @@ paths: type: number required: - message - summary: '' + summary: Delete a proxy tags: - Fleet proxies get: - description: Get proxy by ID + description: Get a proxy by ID. operationId: get-fleet-proxies-itemid parameters: - description: The version of the API to use @@ -34448,11 +34246,11 @@ paths: type: number required: - message - summary: '' + summary: Get a proxy tags: - Fleet proxies put: - description: Update proxy by ID + description: Update a proxy by ID. operationId: put-fleet-proxies-itemid parameters: - description: The version of the API to use @@ -34568,12 +34366,11 @@ paths: type: number required: - message - summary: '' + summary: Update a proxy tags: - Fleet proxies /api/fleet/service_tokens: post: - description: Create a service token operationId: post-fleet-service-tokens parameters: - description: The version of the API to use @@ -34633,12 +34430,11 @@ paths: type: number required: - message - summary: '' + summary: Create a service token tags: - Fleet service tokens /api/fleet/settings: get: - description: Get settings operationId: get-fleet-settings parameters: - description: The version of the API to use @@ -34729,11 +34525,10 @@ paths: type: string required: - message - summary: '' + summary: Get settings tags: - Fleet internals put: - description: Update settings operationId: put-fleet-settings parameters: - description: The version of the API to use @@ -34862,12 +34657,11 @@ paths: type: string required: - message - summary: '' + summary: Update settings tags: - Fleet internals /api/fleet/setup: post: - description: Initiate Fleet setup operationId: post-fleet-setup parameters: - description: The version of the API to use @@ -34944,12 +34738,12 @@ paths: type: string required: - message - summary: '' + summary: Initiate Fleet setup tags: - Fleet internals /api/fleet/uninstall_tokens: get: - description: List metadata for latest uninstall tokens per agent policy + description: List the metadata for the latest uninstall tokens per agent policy. operationId: get-fleet-uninstall-tokens parameters: - description: The version of the API to use @@ -35044,12 +34838,12 @@ paths: type: number required: - message - summary: '' + summary: Get metadata for latest uninstall tokens tags: - Fleet uninstall tokens /api/fleet/uninstall_tokens/{uninstallTokenId}: get: - description: Get one decrypted uninstall token by its ID + description: Get one decrypted uninstall token by its ID. operationId: get-fleet-uninstall-tokens-uninstalltokenid parameters: - description: The version of the API to use @@ -35115,7 +34909,7 @@ paths: type: number required: - message - summary: '' + summary: Get a decrypted uninstall token tags: - Fleet uninstall tokens /api/lists: @@ -37229,7 +37023,7 @@ paths: 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. + objects will be returned in the response body. '400': content: application/json; Elastic-Api-Version=2023-10-31: @@ -37263,7 +37057,7 @@ paths: 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. + objects will be returned in the response body. '400': content: application/json; Elastic-Api-Version=2023-10-31: @@ -58900,7 +58694,7 @@ tags: name: ml - name: roles - description: > - Export sets of saved objects that you want to import into {kib}, resolve + Export sets of saved objects that you want to import into Kibana, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs. diff --git a/oas_docs/overlays/kibana.overlays.serverless.yaml b/oas_docs/overlays/kibana.overlays.serverless.yaml index 64040383ae38..1054f774fe11 100644 --- a/oas_docs/overlays/kibana.overlays.serverless.yaml +++ b/oas_docs/overlays/kibana.overlays.serverless.yaml @@ -4,7 +4,7 @@ info: title: Overlays for the Kibana API document version: 0.0.1 actions: - # Clean up server definitions +# Clean up server definitions - target: '$.servers.*' description: Remove all servers so we can add our own. remove: true @@ -15,12 +15,12 @@ actions: variables: kibana_url: default: localhost:5601 - # Mark all operations as beta +# Mark all operations as beta - target: "$.paths[*]['get','put','post','delete','options','head','patch','trace']" description: Add x-beta update: x-beta: true - # Add some tag descriptions and displayNames +# Add some tag descriptions and displayNames - target: '$.tags[?(@.name=="alerting")]' description: Change tag description and displayName update: @@ -50,6 +50,14 @@ actions: description: Change displayName update: x-displayName: "Machine learning" + - target: '$.tags[?(@.name=="roles")]' + description: Change displayName and description + update: + x-displayName: "Roles" + description: Manage the roles that grant Elasticsearch and Kibana privileges. + externalDocs: + description: Kibana role management + url: https://www.elastic.co/guide/en/kibana/master/kibana-role-management.html - target: '$.tags[?(@.name=="slo")]' description: Change displayName update: @@ -65,7 +73,7 @@ actions: x-displayName: "System" description: > Get information about the system status, resource usage, and installed plugins. - # Remove extra tags from operations +# Remove extra tags from operations - target: "$.paths[*][*].tags[1:]" description: Remove all but first tag from operations remove: true \ No newline at end of file diff --git a/package.json b/package.json index 03e7ff0eeb74..87905c955d2d 100644 --- a/package.json +++ b/package.json @@ -116,9 +116,9 @@ "@elastic/datemath": "5.0.3", "@elastic/ebt": "^1.1.1", "@elastic/ecs": "^8.11.1", - "@elastic/elasticsearch": "^8.15.0", + "@elastic/elasticsearch": "^8.15.2", "@elastic/ems-client": "8.5.3", - "@elastic/eui": "97.3.0", + "@elastic/eui": "97.3.1", "@elastic/filesaver": "1.1.2", "@elastic/node-crypto": "^1.2.3", "@elastic/numeral": "^2.5.1", @@ -567,6 +567,7 @@ "@kbn/i18n-react": "link:packages/kbn-i18n-react", "@kbn/iframe-embedded-plugin": "link:x-pack/test/functional_embedded/plugins/iframe_embedded", "@kbn/image-embeddable-plugin": "link:src/plugins/image_embeddable", + "@kbn/index-lifecycle-management-common-shared": "link:x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared", "@kbn/index-lifecycle-management-plugin": "link:x-pack/plugins/index_lifecycle_management", "@kbn/index-management-plugin": "link:x-pack/plugins/index_management", "@kbn/index-management-shared-types": "link:x-pack/packages/index-management/index_management_shared_types", @@ -1062,7 +1063,7 @@ "@turf/length": "^6.0.2", "@xstate/react": "^3.2.2", "@xstate5/react": "npm:@xstate/react@^4.1.2", - "@xyflow/react": "^12.3.2", + "@xyflow/react": "^12.3.4", "adm-zip": "^0.5.9", "ai": "^2.2.33", "ajv": "^8.12.0", @@ -1197,13 +1198,13 @@ "p-settle": "4.1.1", "papaparse": "^5.2.0", "pbf": "3.2.1", - "pdfmake": "^0.2.7", + "pdfmake": "^0.2.15", "peggy": "^1.2.0", "polished": "^3.7.2", "pretty-ms": "6.0.0", "prop-types": "^15.8.1", "proxy-from-env": "1.0.0", - "puppeteer": "23.3.1", + "puppeteer": "23.7.0", "query-string": "^6.13.2", "rbush": "^3.0.1", "re-resizable": "^6.9.9", @@ -1497,7 +1498,7 @@ "@octokit/rest": "^17.11.2", "@parcel/watcher": "^2.1.0", "@playwright/test": "=1.46.0", - "@redocly/cli": "^1.25.9", + "@redocly/cli": "^1.25.11", "@statoscope/webpack-plugin": "^5.28.2", "@storybook/addon-a11y": "^6.5.16", "@storybook/addon-actions": "^6.5.16", @@ -1517,9 +1518,9 @@ "@storybook/react": "^6.5.16", "@storybook/testing-react": "^1.3.0", "@storybook/theming": "^6.5.16", - "@testing-library/dom": "^8.19.0", + "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.5.0", - "@testing-library/react": "^12.1.5", + "@testing-library/react": "^16.0.1", "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "^14.5.2", "@types/adm-zip": "^0.5.0", @@ -1690,6 +1691,7 @@ "cypress-axe": "^1.5.0", "cypress-file-upload": "^5.0.8", "cypress-multi-reporters": "^1.6.4", + "cypress-network-idle": "^1.14.2", "cypress-real-events": "^1.11.0", "cypress-recurse": "^1.35.2", "date-fns": "^2.29.3", diff --git a/packages/core/deprecations/core-deprecations-common/index.ts b/packages/core/deprecations/core-deprecations-common/index.ts index 005e84d7d57f..de8122a18c55 100644 --- a/packages/core/deprecations/core-deprecations-common/index.ts +++ b/packages/core/deprecations/core-deprecations-common/index.ts @@ -11,6 +11,7 @@ export type { BaseDeprecationDetails, ConfigDeprecationDetails, FeatureDeprecationDetails, + ApiDeprecationDetails, DeprecationsDetails, DomainDeprecationDetails, DeprecationsGetResponse, diff --git a/packages/core/deprecations/core-deprecations-common/src/types.ts b/packages/core/deprecations/core-deprecations-common/src/types.ts index 85da30b2c128..9a08be780845 100644 --- a/packages/core/deprecations/core-deprecations-common/src/types.ts +++ b/packages/core/deprecations/core-deprecations-common/src/types.ts @@ -121,7 +121,7 @@ export type DeprecationsDetails = /** * @public */ -export type DomainDeprecationDetails = DeprecationsDetails & { +export type DomainDeprecationDetails = ExtendedDetails & { domainId: string; }; diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations.ts deleted file mode 100644 index 45893987ddf9..000000000000 --- a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations.ts +++ /dev/null @@ -1,96 +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 type { InternalHttpServiceSetup } from '@kbn/core-http-server-internal'; -import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; -import type { RouterDeprecatedRouteDetails } from '@kbn/core-http-server'; -import { DeprecationsDetails } from '@kbn/core-deprecations-common'; -import type { DeprecationsFactory } from '../deprecations_factory'; -import { - getApiDeprecationMessage, - getApiDeprecationsManualSteps, - getApiDeprecationTitle, -} from './i18n_texts'; - -interface ApiDeprecationsServiceDeps { - deprecationsFactory: DeprecationsFactory; - http: InternalHttpServiceSetup; - coreUsageData: InternalCoreUsageDataSetup; -} - -export const buildApiDeprecationId = ({ - routePath, - routeMethod, - routeVersion, -}: Pick): string => { - return [ - routeVersion || 'unversioned', - routeMethod.toLocaleLowerCase(), - routePath.replace(/\/$/, ''), - ].join('|'); -}; - -export const createGetApiDeprecations = - ({ http, coreUsageData }: Pick) => - async (): Promise => { - const deprecatedRoutes = http.getRegisteredDeprecatedApis(); - const usageClient = coreUsageData.getClient(); - const deprecatedApiUsageStats = await usageClient.getDeprecatedApiUsageStats(); - - return deprecatedApiUsageStats - .filter(({ apiTotalCalls, totalMarkedAsResolved }) => { - return apiTotalCalls > totalMarkedAsResolved; - }) - .filter(({ apiId }) => - deprecatedRoutes.some((routeDetails) => buildApiDeprecationId(routeDetails) === apiId) - ) - .map((apiUsageStats) => { - const { apiId, apiTotalCalls, totalMarkedAsResolved } = apiUsageStats; - const routeDeprecationDetails = deprecatedRoutes.find( - (routeDetails) => buildApiDeprecationId(routeDetails) === apiId - )!; - const { routeVersion, routePath, routeDeprecationOptions, routeMethod } = - routeDeprecationDetails; - - const deprecationLevel = routeDeprecationOptions.severity || 'warning'; - - return { - apiId, - title: getApiDeprecationTitle(routeDeprecationDetails), - level: deprecationLevel, - message: getApiDeprecationMessage(routeDeprecationDetails, apiUsageStats), - documentationUrl: routeDeprecationOptions.documentationUrl, - correctiveActions: { - manualSteps: getApiDeprecationsManualSteps(routeDeprecationDetails), - mark_as_resolved_api: { - routePath, - routeMethod, - routeVersion, - apiTotalCalls, - totalMarkedAsResolved, - timestamp: new Date(), - }, - }, - deprecationType: 'api', - domainId: 'core.routes-deprecations', - }; - }); - }; - -export const registerApiDeprecationsInfo = ({ - deprecationsFactory, - http, - coreUsageData, -}: ApiDeprecationsServiceDeps): void => { - const deprecationsRegistery = deprecationsFactory.getRegistry('core.api_deprecations'); - - deprecationsRegistery.registerDeprecations({ - getDeprecations: createGetApiDeprecations({ http, coreUsageData }), - }); -}; diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/access/access_deprecations.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/access/access_deprecations.ts new file mode 100644 index 000000000000..2a0c2a8cae5f --- /dev/null +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/access/access_deprecations.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", 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 { + ApiDeprecationDetails, + DomainDeprecationDetails, +} from '@kbn/core-deprecations-common'; + +import type { PostValidationMetadata } from '@kbn/core-http-server'; +import type { BuildApiDeprecationDetailsParams } from '../types'; +import { + getApiDeprecationMessage, + getApiDeprecationsManualSteps, + getApiDeprecationTitle, +} from './i18n_texts'; + +export const getIsAccessApiDeprecation = ({ + isInternalApiRequest, + isPublicAccess, +}: PostValidationMetadata): boolean => { + const isNotPublicAccess = !isPublicAccess; + const isNotInternalRequest = !isInternalApiRequest; + + return !!(isNotPublicAccess && isNotInternalRequest); +}; + +export const buildApiAccessDeprecationDetails = ({ + apiUsageStats, + deprecatedApiDetails, +}: BuildApiDeprecationDetailsParams): DomainDeprecationDetails => { + const { apiId, apiTotalCalls, totalMarkedAsResolved } = apiUsageStats; + const { routeVersion, routePath, routeDeprecationOptions, routeMethod } = deprecatedApiDetails; + + const deprecationLevel = routeDeprecationOptions?.severity || 'warning'; + + return { + apiId, + title: getApiDeprecationTitle(deprecatedApiDetails), + level: deprecationLevel, + message: getApiDeprecationMessage(deprecatedApiDetails, apiUsageStats), + documentationUrl: routeDeprecationOptions?.documentationUrl, + correctiveActions: { + manualSteps: getApiDeprecationsManualSteps(), + mark_as_resolved_api: { + routePath, + routeMethod, + routeVersion, + apiTotalCalls, + totalMarkedAsResolved, + timestamp: new Date(), + }, + }, + deprecationType: 'api', + domainId: 'core.http.access-deprecations', + }; +}; diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/access/i18n_texts.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/access/i18n_texts.ts new file mode 100644 index 000000000000..bd1f92cf368f --- /dev/null +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/access/i18n_texts.ts @@ -0,0 +1,101 @@ +/* + * Copyright 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 { RouterDeprecatedApiDetails } from '@kbn/core-http-server'; +import { CoreDeprecatedApiUsageStats } from '@kbn/core-usage-data-server'; +import { i18n } from '@kbn/i18n'; +import moment from 'moment'; + +export const getApiDeprecationTitle = ( + details: Pick +) => { + const { routePath, routeMethod } = details; + const routeWithMethod = `${routeMethod.toUpperCase()} ${routePath}`; + + return i18n.translate('core.deprecations.apiAccessDeprecation.infoTitle', { + defaultMessage: 'The "{routeWithMethod}" API is internal to Elastic', + values: { + routeWithMethod, + }, + }); +}; + +export const getApiDeprecationMessage = ( + details: Pick< + RouterDeprecatedApiDetails, + 'routePath' | 'routeMethod' | 'routeDeprecationOptions' + >, + apiUsageStats: CoreDeprecatedApiUsageStats +): string[] => { + const { routePath, routeMethod, routeDeprecationOptions } = details; + const { apiLastCalledAt, apiTotalCalls, markedAsResolvedLastCalledAt, totalMarkedAsResolved } = + apiUsageStats; + + const diff = apiTotalCalls - totalMarkedAsResolved; + const wasResolvedBefore = totalMarkedAsResolved > 0; + const routeWithMethod = `${routeMethod.toUpperCase()} ${routePath}`; + + const messages = [ + i18n.translate('core.deprecations.apiAccessDeprecation.apiCallsDetailsMessage', { + defaultMessage: + 'The API "{routeWithMethod}" has been called {apiTotalCalls} times. The last call was on {apiLastCalledAt}.', + values: { + routeWithMethod, + apiTotalCalls, + apiLastCalledAt: moment(apiLastCalledAt).format('LLLL Z'), + }, + }), + ]; + + if (wasResolvedBefore) { + messages.push( + i18n.translate('core.deprecations.apiAccessDeprecation.previouslyMarkedAsResolvedMessage', { + defaultMessage: + 'This issue has been marked as resolved on {markedAsResolvedLastCalledAt} but the API has been called {timeSinceLastResolved, plural, one {# time} other {# times}} since.', + values: { + timeSinceLastResolved: diff, + markedAsResolvedLastCalledAt: moment(markedAsResolvedLastCalledAt).format('LLLL Z'), + }, + }) + ); + } + + messages.push( + i18n.translate('core.deprecations.apiAccessDeprecation.internalApiExplanationMessage', { + defaultMessage: + 'Internal APIs are meant to be used by Elastic services only. You should not use them. External access to these APIs will be restricted.', + }) + ); + + if (routeDeprecationOptions?.message) { + // Surfaces additional deprecation messages passed into the route in UA + messages.push(routeDeprecationOptions.message); + } + + return messages; +}; + +export const getApiDeprecationsManualSteps = (): string[] => { + return [ + i18n.translate('core.deprecations.apiAccessDeprecation.manualSteps.identifyCallsOriginStep', { + defaultMessage: 'Identify the origin of these API calls.', + }), + i18n.translate('core.deprecations.apiAccessDeprecation.manualSteps.deleteRequestsStep', { + defaultMessage: + 'Delete any requests you have that use this API. Check the learn more link for possible alternatives.', + }), + i18n.translate( + 'core.deprecations.apiAccessDeprecation.manualSteps.accessDepractionMarkAsResolvedStep', + { + defaultMessage: + 'Once you have successfully stopped using this API, mark this issue as resolved. It will no longer appear in the Upgrade Assistant unless another call using this API is detected.', + } + ), + ]; +}; diff --git a/src/plugins/dashboard/server/content_management/schema/v2/index.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/access/index.ts similarity index 80% rename from src/plugins/dashboard/server/content_management/schema/v2/index.ts rename to packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/access/index.ts index 66beda1385d0..b78ddba35d2c 100644 --- a/src/plugins/dashboard/server/content_management/schema/v2/index.ts +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/access/index.ts @@ -7,8 +7,4 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export { - serviceDefinition, - dashboardSavedObjectSchema, - dashboardAttributesSchema, -} from './cm_services'; +export { buildApiAccessDeprecationDetails, getIsAccessApiDeprecation } from './access_deprecations'; diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/api_deprecation_id.test.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/api_deprecation_id.test.ts new file mode 100644 index 000000000000..151b7bd8d4ce --- /dev/null +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/api_deprecation_id.test.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 { buildApiDeprecationId } from './api_deprecation_id'; + +describe('#buildApiDeprecationId', () => { + it('returns apiDeprecationId string for versioned routes', () => { + const apiDeprecationId = buildApiDeprecationId({ + routeMethod: 'get', + routePath: '/api/test', + routeVersion: '10-10-2023', + }); + expect(apiDeprecationId).toBe('10-10-2023|get|/api/test'); + }); + + it('returns apiDeprecationId string for unversioned routes', () => { + const apiDeprecationId = buildApiDeprecationId({ + routeMethod: 'get', + routePath: '/api/test', + }); + expect(apiDeprecationId).toBe('unversioned|get|/api/test'); + }); + + it('gives the same ID the route method is capitalized or not', () => { + const apiDeprecationId = buildApiDeprecationId({ + // @ts-expect-error + routeMethod: 'GeT', + routePath: '/api/test', + routeVersion: '10-10-2023', + }); + + expect(apiDeprecationId).toBe('10-10-2023|get|/api/test'); + }); + + it('gives the same ID the route path has a trailing slash or not', () => { + const apiDeprecationId = buildApiDeprecationId({ + // @ts-expect-error + routeMethod: 'GeT', + routePath: '/api/test/', + routeVersion: '10-10-2023', + }); + + expect(apiDeprecationId).toBe('10-10-2023|get|/api/test'); + }); +}); diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/api_deprecation_id.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/api_deprecation_id.ts new file mode 100644 index 000000000000..0e3b6107a25e --- /dev/null +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/api_deprecation_id.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", 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 { RouterDeprecatedApiDetails } from '@kbn/core-http-server'; + +export const buildApiDeprecationId = ({ + routePath, + routeMethod, + routeVersion, +}: Pick): string => { + return [ + routeVersion || 'unversioned', + routeMethod.toLocaleLowerCase(), + routePath.replace(/\/$/, ''), + ].join('|'); +}; diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/index.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/index.ts new file mode 100644 index 000000000000..8d823e8ad211 --- /dev/null +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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". + */ + +export { registerApiDeprecationsInfo } from './register_api_depercation_info'; +export { getIsAccessApiDeprecation } from './access'; +export { getIsRouteApiDeprecation } from './route'; +export { buildApiDeprecationId } from './api_deprecation_id'; diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations.test.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/register_api_depercation_info.test.ts similarity index 89% rename from packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations.test.ts rename to packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/register_api_depercation_info.test.ts index 5f9d0bfbb4b8..9a7842d8915d 100644 --- a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations.test.ts +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/register_api_depercation_info.test.ts @@ -8,13 +8,13 @@ */ import type { DeepPartial } from '@kbn/utility-types'; -import { mockDeprecationsRegistry, mockDeprecationsFactory } from '../mocks'; +import { mockDeprecationsRegistry, mockDeprecationsFactory } from '../../mocks'; import { registerApiDeprecationsInfo, - buildApiDeprecationId, createGetApiDeprecations, -} from './api_deprecations'; -import { RouterDeprecatedRouteDetails } from '@kbn/core-http-server'; +} from './register_api_depercation_info'; +import { buildApiDeprecationId } from './api_deprecation_id'; +import { RouterDeprecatedApiDetails } from '@kbn/core-http-server'; import { httpServiceMock } from '@kbn/core-http-server-mocks'; import { coreUsageDataServiceMock, @@ -58,10 +58,11 @@ describe('#registerApiDeprecationsInfo', () => { describe('#createGetApiDeprecations', () => { const createDeprecatedRouteDetails = ( - overrides?: DeepPartial - ): RouterDeprecatedRouteDetails => + overrides?: DeepPartial + ): RouterDeprecatedApiDetails => _.merge( { + routeAccess: 'public', routeDeprecationOptions: { documentationUrl: 'https://fake-url', severity: 'critical', @@ -72,7 +73,7 @@ describe('#registerApiDeprecationsInfo', () => { routeMethod: 'get', routePath: '/api/test/', routeVersion: '123', - } as RouterDeprecatedRouteDetails, + } as RouterDeprecatedApiDetails, overrides ); @@ -124,7 +125,7 @@ describe('#registerApiDeprecationsInfo', () => { }, "deprecationType": "api", "documentationUrl": "https://fake-url", - "domainId": "core.routes-deprecations", + "domainId": "core.http.routes-deprecations", "level": "critical", "message": Array [ "The API \\"GET /api/test_removed/\\" has been called 13 times. The last call was on Sunday, September 1, 2024 6:06 AM -04:00.", @@ -171,7 +172,7 @@ describe('#registerApiDeprecationsInfo', () => { }, "deprecationType": "api", "documentationUrl": "https://fake-url", - "domainId": "core.routes-deprecations", + "domainId": "core.http.routes-deprecations", "level": "critical", "message": Array [ "The API \\"GET /api/test_migrated/\\" has been called 13 times. The last call was on Sunday, September 1, 2024 6:06 AM -04:00.", @@ -216,7 +217,7 @@ describe('#registerApiDeprecationsInfo', () => { }, "deprecationType": "api", "documentationUrl": "https://fake-url", - "domainId": "core.routes-deprecations", + "domainId": "core.http.routes-deprecations", "level": "critical", "message": Array [ "The API \\"GET /api/test_bumped/\\" has been called 13 times. The last call was on Sunday, September 1, 2024 6:06 AM -04:00.", @@ -260,7 +261,7 @@ describe('#registerApiDeprecationsInfo', () => { }, "deprecationType": "api", "documentationUrl": "https://fake-url", - "domainId": "core.routes-deprecations", + "domainId": "core.http.routes-deprecations", "level": "critical", "message": Array [ "The API \\"GET /api/test_deprecated/\\" has been called 13 times. The last call was on Sunday, September 1, 2024 6:06 AM -04:00.", @@ -323,7 +324,7 @@ describe('#registerApiDeprecationsInfo', () => { }, "deprecationType": "api", "documentationUrl": "https://fake-url", - "domainId": "core.routes-deprecations", + "domainId": "core.http.routes-deprecations", "level": "critical", "message": Array [ "The API \\"GET /api/test_never_resolved/\\" has been called 13 times. The last call was on Sunday, September 1, 2024 6:06 AM -04:00.", @@ -355,44 +356,3 @@ describe('#registerApiDeprecationsInfo', () => { }); }); }); - -describe('#buildApiDeprecationId', () => { - it('returns apiDeprecationId string for versioned routes', () => { - const apiDeprecationId = buildApiDeprecationId({ - routeMethod: 'get', - routePath: '/api/test', - routeVersion: '10-10-2023', - }); - expect(apiDeprecationId).toBe('10-10-2023|get|/api/test'); - }); - - it('returns apiDeprecationId string for unversioned routes', () => { - const apiDeprecationId = buildApiDeprecationId({ - routeMethod: 'get', - routePath: '/api/test', - }); - expect(apiDeprecationId).toBe('unversioned|get|/api/test'); - }); - - it('gives the same ID the route method is capitalized or not', () => { - const apiDeprecationId = buildApiDeprecationId({ - // @ts-expect-error - routeMethod: 'GeT', - routePath: '/api/test', - routeVersion: '10-10-2023', - }); - - expect(apiDeprecationId).toBe('10-10-2023|get|/api/test'); - }); - - it('gives the same ID the route path has a trailing slash or not', () => { - const apiDeprecationId = buildApiDeprecationId({ - // @ts-expect-error - routeMethod: 'GeT', - routePath: '/api/test/', - routeVersion: '10-10-2023', - }); - - expect(apiDeprecationId).toBe('10-10-2023|get|/api/test'); - }); -}); diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/register_api_depercation_info.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/register_api_depercation_info.ts new file mode 100644 index 000000000000..f4c9847b09e5 --- /dev/null +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/register_api_depercation_info.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", 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 { DeprecationsDetails } from '@kbn/core-deprecations-common'; + +import { buildApiRouteDeprecationDetails } from './route/route_deprecations'; +import { buildApiAccessDeprecationDetails } from './access/access_deprecations'; +import { buildApiDeprecationId } from './api_deprecation_id'; +import type { ApiDeprecationsServiceDeps } from './types'; + +export const createGetApiDeprecations = + ({ http, coreUsageData }: Pick) => + async (): Promise => { + const usageClient = coreUsageData.getClient(); + const deprecatedApis = http.getRegisteredDeprecatedApis(); + const deprecatedApiUsageStats = await usageClient.getDeprecatedApiUsageStats(); + + return deprecatedApiUsageStats + .filter(({ apiTotalCalls, totalMarkedAsResolved }) => { + return apiTotalCalls > totalMarkedAsResolved; + }) + .filter(({ apiId }) => + deprecatedApis.some((routeDetails) => buildApiDeprecationId(routeDetails) === apiId) + ) + .map((apiUsageStats) => { + const { apiId } = apiUsageStats; + const deprecatedApiDetails = deprecatedApis.find( + (routeDetails) => buildApiDeprecationId(routeDetails) === apiId + ); + if (!deprecatedApiDetails) { + throw new Error(`Unable to find deprecation details for "${apiId}"`); + } + + const { routeAccess } = deprecatedApiDetails; + switch (routeAccess) { + case 'public': { + return buildApiRouteDeprecationDetails({ + apiUsageStats, + deprecatedApiDetails, + }); + } + // if no access is specified then internal is the default + case 'internal': + default: { + return buildApiAccessDeprecationDetails({ + apiUsageStats, + deprecatedApiDetails, + }); + } + } + }); + }; + +export const registerApiDeprecationsInfo = ({ + deprecationsFactory, + http, + coreUsageData, +}: ApiDeprecationsServiceDeps): void => { + const deprecationsRegistery = deprecationsFactory.getRegistry('core.api_deprecations'); + + deprecationsRegistery.registerDeprecations({ + getDeprecations: createGetApiDeprecations({ http, coreUsageData }), + }); +}; diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/i18n_texts.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/route/i18n_texts.ts similarity index 67% rename from packages/core/deprecations/core-deprecations-server-internal/src/deprecations/i18n_texts.ts rename to packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/route/i18n_texts.ts index e52dd1f3d8fd..8cbade658bb2 100644 --- a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/i18n_texts.ts +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/route/i18n_texts.ts @@ -7,22 +7,26 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { RouterDeprecatedRouteDetails } from '@kbn/core-http-server'; +import { RouterDeprecatedApiDetails } from '@kbn/core-http-server'; import { CoreDeprecatedApiUsageStats } from '@kbn/core-usage-data-server'; import { i18n } from '@kbn/i18n'; import moment from 'moment'; -export const getApiDeprecationTitle = (details: RouterDeprecatedRouteDetails) => { +export const getApiDeprecationTitle = (details: RouterDeprecatedApiDetails) => { const { routePath, routeMethod, routeDeprecationOptions } = details; + if (!routeDeprecationOptions) { + throw new Error(`Router "deprecated" param is missing for path "${routePath}".`); + } + const deprecationType = routeDeprecationOptions.reason.type; const routeWithMethod = `${routeMethod.toUpperCase()} ${routePath}`; - const deprecationTypeText = i18n.translate('core.deprecations.deprecations.apiDeprecationType', { + const deprecationTypeText = i18n.translate('core.deprecations.apiRouteDeprecation.type', { defaultMessage: '{deprecationType, select, remove {is removed} bump {has a newer version available} migrate {is migrated to a different API} other {is deprecated}}', values: { deprecationType }, }); - return i18n.translate('core.deprecations.deprecations.apiDeprecationInfoTitle', { + return i18n.translate('core.deprecations.apiRouteDeprecation.infoTitle', { defaultMessage: 'The "{routeWithMethod}" route {deprecationTypeText}', values: { routeWithMethod, @@ -32,10 +36,13 @@ export const getApiDeprecationTitle = (details: RouterDeprecatedRouteDetails) => }; export const getApiDeprecationMessage = ( - details: RouterDeprecatedRouteDetails, + details: RouterDeprecatedApiDetails, apiUsageStats: CoreDeprecatedApiUsageStats ): string[] => { const { routePath, routeMethod, routeDeprecationOptions } = details; + if (!routeDeprecationOptions) { + throw new Error(`Router "deprecated" param is missing for path "${routePath}".`); + } const { apiLastCalledAt, apiTotalCalls, markedAsResolvedLastCalledAt, totalMarkedAsResolved } = apiUsageStats; @@ -44,7 +51,7 @@ export const getApiDeprecationMessage = ( const routeWithMethod = `${routeMethod.toUpperCase()} ${routePath}`; const messages = [ - i18n.translate('core.deprecations.deprecations.apiDeprecationApiCallsDetailsMessage', { + i18n.translate('core.deprecations.apiRouteDeprecation.apiCallsDetailsMessage', { defaultMessage: 'The API "{routeWithMethod}" has been called {apiTotalCalls} times. The last call was on {apiLastCalledAt}.', values: { @@ -57,17 +64,14 @@ export const getApiDeprecationMessage = ( if (wasResolvedBefore) { messages.push( - i18n.translate( - 'core.deprecations.deprecations.apiDeprecationPreviouslyMarkedAsResolvedMessage', - { - defaultMessage: - 'This issue has been marked as resolved on {markedAsResolvedLastCalledAt} but the API has been called {timeSinceLastResolved, plural, one {# time} other {# times}} since.', - values: { - timeSinceLastResolved: diff, - markedAsResolvedLastCalledAt: moment(markedAsResolvedLastCalledAt).format('LLLL Z'), - }, - } - ) + i18n.translate('core.deprecations.apiRouteDeprecation.previouslyMarkedAsResolvedMessage', { + defaultMessage: + 'This issue has been marked as resolved on {markedAsResolvedLastCalledAt} but the API has been called {timeSinceLastResolved, plural, one {# time} other {# times}} since.', + values: { + timeSinceLastResolved: diff, + markedAsResolvedLastCalledAt: moment(markedAsResolvedLastCalledAt).format('LLLL Z'), + }, + }) ); } @@ -79,12 +83,16 @@ export const getApiDeprecationMessage = ( return messages; }; -export const getApiDeprecationsManualSteps = (details: RouterDeprecatedRouteDetails): string[] => { - const { routeDeprecationOptions } = details; +export const getApiDeprecationsManualSteps = (details: RouterDeprecatedApiDetails): string[] => { + const { routePath, routeDeprecationOptions } = details; + if (!routeDeprecationOptions) { + throw new Error(`Router "deprecated" param is missing for path "${routePath}".`); + } + const deprecationType = routeDeprecationOptions.reason.type; const manualSteps = [ - i18n.translate('core.deprecations.deprecations.manualSteps.apiIseprecatedStep', { + i18n.translate('core.deprecations.apiRouteDeprecation.manualSteps.identifyCallsOriginStep', { defaultMessage: 'Identify the origin of these API calls.', }), ]; @@ -93,7 +101,7 @@ export const getApiDeprecationsManualSteps = (details: RouterDeprecatedRouteDeta case 'bump': { const { newApiVersion } = routeDeprecationOptions.reason; manualSteps.push( - i18n.translate('core.deprecations.deprecations.manualSteps.bumpDetailsStep', { + i18n.translate('core.deprecations.apiRouteDeprecation.manualSteps.bumpTypeStep', { defaultMessage: 'Update the requests to use the following new version of the API instead: "{newApiVersion}".', values: { newApiVersion }, @@ -104,7 +112,7 @@ export const getApiDeprecationsManualSteps = (details: RouterDeprecatedRouteDeta case 'remove': { manualSteps.push( - i18n.translate('core.deprecations.deprecations.manualSteps.removeTypeExplainationStep', { + i18n.translate('core.deprecations.apiRouteDeprecation.manualSteps.removeTypeStep', { defaultMessage: 'This API no longer exists and no replacement is available. Delete any requests you have that use this API.', }) @@ -113,7 +121,7 @@ export const getApiDeprecationsManualSteps = (details: RouterDeprecatedRouteDeta } case 'deprecate': { manualSteps.push( - i18n.translate('core.deprecations.deprecations.manualSteps.removeTypeExplainationStep', { + i18n.translate('core.deprecations.apiRouteDeprecation.manualSteps.deprecateTypeStep', { defaultMessage: 'For now, the API will still work, but will be moved or removed in a future version. Check the Learn more link for more information. If you are no longer using the API, you can mark this issue as resolved. It will no longer appear in the Upgrade Assistant unless another call using this API is detected.', }) @@ -125,7 +133,7 @@ export const getApiDeprecationsManualSteps = (details: RouterDeprecatedRouteDeta const newRouteWithMethod = `${newApiMethod.toUpperCase()} ${newApiPath}`; manualSteps.push( - i18n.translate('core.deprecations.deprecations.manualSteps.migrateDetailsStep', { + i18n.translate('core.deprecations.apiRouteDeprecation.manualSteps.migrateTypeStep', { defaultMessage: 'Update the requests to use the following new API instead: "{newRouteWithMethod}".', values: { newRouteWithMethod }, @@ -137,10 +145,13 @@ export const getApiDeprecationsManualSteps = (details: RouterDeprecatedRouteDeta if (deprecationType !== 'deprecate') { manualSteps.push( - i18n.translate('core.deprecations.deprecations.manualSteps.markAsResolvedStep', { - defaultMessage: - 'Check that you are no longer using the old API in any requests, and mark this issue as resolved. It will no longer appear in the Upgrade Assistant unless another call using this API is detected.', - }) + i18n.translate( + 'core.deprecations.apiRouteDeprecation.manualSteps.routeDepractionMarkAsResolvedStep', + { + defaultMessage: + 'Check that you are no longer using the old API in any requests, and mark this issue as resolved. It will no longer appear in the Upgrade Assistant unless another call using this API is detected.', + } + ) ); } diff --git a/src/plugins/dashboard/server/content_management/schema/v1/index.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/route/index.ts similarity index 77% rename from src/plugins/dashboard/server/content_management/schema/v1/index.ts rename to packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/route/index.ts index c26552457e5f..9caf06c7def8 100644 --- a/src/plugins/dashboard/server/content_management/schema/v1/index.ts +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/route/index.ts @@ -7,9 +7,4 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export { - serviceDefinition, - dashboardSavedObjectSchema, - controlGroupInputSchema, - dashboardAttributesSchema, -} from './cm_services'; +export { buildApiRouteDeprecationDetails, getIsRouteApiDeprecation } from './route_deprecations'; diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/route/route_deprecations.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/route/route_deprecations.ts new file mode 100644 index 000000000000..6f9bab78dff9 --- /dev/null +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/route/route_deprecations.ts @@ -0,0 +1,65 @@ +/* + * Copyright 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 { + ApiDeprecationDetails, + DomainDeprecationDetails, +} from '@kbn/core-deprecations-common'; +import _ from 'lodash'; +import type { PostValidationMetadata } from '@kbn/core-http-server'; +import { + getApiDeprecationMessage, + getApiDeprecationsManualSteps, + getApiDeprecationTitle, +} from './i18n_texts'; +import type { BuildApiDeprecationDetailsParams } from '../types'; + +export const getIsRouteApiDeprecation = ({ + isInternalApiRequest, + deprecated, +}: PostValidationMetadata): boolean => { + const hasDeprecatedObject = deprecated && _.isObject(deprecated); + const isNotInternalRequest = !isInternalApiRequest; + + return !!(hasDeprecatedObject && isNotInternalRequest); +}; + +export const buildApiRouteDeprecationDetails = ({ + apiUsageStats, + deprecatedApiDetails, +}: BuildApiDeprecationDetailsParams): DomainDeprecationDetails => { + const { apiId, apiTotalCalls, totalMarkedAsResolved } = apiUsageStats; + const { routeVersion, routePath, routeDeprecationOptions, routeMethod } = deprecatedApiDetails; + if (!routeDeprecationOptions) { + throw new Error(`Expecing deprecated to be defined for route ${apiId}`); + } + + const deprecationLevel = routeDeprecationOptions.severity || 'warning'; + + return { + apiId, + title: getApiDeprecationTitle(deprecatedApiDetails), + level: deprecationLevel, + message: getApiDeprecationMessage(deprecatedApiDetails, apiUsageStats), + documentationUrl: routeDeprecationOptions.documentationUrl, + correctiveActions: { + manualSteps: getApiDeprecationsManualSteps(deprecatedApiDetails), + mark_as_resolved_api: { + routePath, + routeMethod, + routeVersion, + apiTotalCalls, + totalMarkedAsResolved, + timestamp: new Date(), + }, + }, + deprecationType: 'api', + domainId: 'core.http.routes-deprecations', + }; +}; diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/types.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/types.ts new file mode 100644 index 000000000000..ad6436b70c55 --- /dev/null +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/api_deprecations/types.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", 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 { InternalHttpServiceSetup } from '@kbn/core-http-server-internal'; +import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; +import type { RouterDeprecatedApiDetails } from '@kbn/core-http-server'; +import type { CoreDeprecatedApiUsageStats } from '@kbn/core-usage-data-server'; +import type { DeprecationsFactory } from '../../deprecations_factory'; + +export interface ApiDeprecationsServiceDeps { + deprecationsFactory: DeprecationsFactory; + http: InternalHttpServiceSetup; + coreUsageData: InternalCoreUsageDataSetup; +} + +export interface BuildApiDeprecationDetailsParams { + apiUsageStats: CoreDeprecatedApiUsageStats; + deprecatedApiDetails: RouterDeprecatedApiDetails; +} diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/index.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/index.ts index aecf3d5b299a..21e4f801ca98 100644 --- a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/index.ts +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations/index.ts @@ -7,5 +7,10 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export { buildApiDeprecationId, registerApiDeprecationsInfo } from './api_deprecations'; +export { + buildApiDeprecationId, + registerApiDeprecationsInfo, + getIsAccessApiDeprecation, + getIsRouteApiDeprecation, +} from './api_deprecations'; export { registerConfigDeprecationsInfo } from './config_deprecations'; diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations_service.test.ts b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations_service.test.ts index 39c299d98053..0ea283b6eb5d 100644 --- a/packages/core/deprecations/core-deprecations-server-internal/src/deprecations_service.test.ts +++ b/packages/core/deprecations/core-deprecations-server-internal/src/deprecations_service.test.ts @@ -52,7 +52,10 @@ describe('DeprecationsService', () => { expect(http.createRouter).toBeCalledWith('/api/deprecations'); // registers get route '/' expect(router.get).toHaveBeenCalledTimes(1); - expect(router.get).toHaveBeenCalledWith({ path: '/', validate: false }, expect.any(Function)); + expect(router.get).toHaveBeenCalledWith( + { options: { access: 'public' }, path: '/', validate: false }, + expect.any(Function) + ); }); it('calls registerConfigDeprecationsInfo', async () => { diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/routes/get.ts b/packages/core/deprecations/core-deprecations-server-internal/src/routes/get.ts index ed3cd061b633..42a2af4ff7d1 100644 --- a/packages/core/deprecations/core-deprecations-server-internal/src/routes/get.ts +++ b/packages/core/deprecations/core-deprecations-server-internal/src/routes/get.ts @@ -14,6 +14,9 @@ export const registerGetRoute = (router: InternalDeprecationRouter) => { router.get( { path: '/', + options: { + access: 'public', + }, validate: false, }, async (context, req, res) => { diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/routes/post_validation_handler.ts b/packages/core/deprecations/core-deprecations-server-internal/src/routes/post_validation_handler.ts index b93c17af2f53..20f680d4c313 100644 --- a/packages/core/deprecations/core-deprecations-server-internal/src/routes/post_validation_handler.ts +++ b/packages/core/deprecations/core-deprecations-server-internal/src/routes/post_validation_handler.ts @@ -10,9 +10,9 @@ import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-server-internal'; import type { CoreKibanaRequest } from '@kbn/core-http-router-server-internal'; import type { InternalHttpServiceSetup } from '@kbn/core-http-server-internal'; -import { isObject } from 'lodash'; -import { RouteDeprecationInfo } from '@kbn/core-http-server/src/router/route'; +import type { PostValidationMetadata } from '@kbn/core-http-server'; import { buildApiDeprecationId } from '../deprecations'; +import { getIsRouteApiDeprecation, getIsAccessApiDeprecation } from '../deprecations'; interface Dependencies { coreUsageData: InternalCoreUsageDataSetup; @@ -35,8 +35,11 @@ export function createRouteDeprecationsHandler({ }: { coreUsageData: InternalCoreUsageDataSetup; }) { - return (req: CoreKibanaRequest, { deprecated }: { deprecated?: RouteDeprecationInfo }) => { - if (deprecated && isObject(deprecated) && req.route.routePath) { + return (req: CoreKibanaRequest, metadata: PostValidationMetadata) => { + const hasRouteDeprecation = getIsRouteApiDeprecation(metadata); + const hasAccessDeprecation = getIsAccessApiDeprecation(metadata); + const isApiDeprecation = hasAccessDeprecation || hasRouteDeprecation; + if (isApiDeprecation && req.route.routePath) { const counterName = buildApiDeprecationId({ routeMethod: req.route.method, routePath: req.route.routePath, diff --git a/packages/core/deprecations/core-deprecations-server-internal/src/routes/resolve_deprecated_api.ts b/packages/core/deprecations/core-deprecations-server-internal/src/routes/resolve_deprecated_api.ts index 840bc5ac22d2..14939188ef0f 100644 --- a/packages/core/deprecations/core-deprecations-server-internal/src/routes/resolve_deprecated_api.ts +++ b/packages/core/deprecations/core-deprecations-server-internal/src/routes/resolve_deprecated_api.ts @@ -19,6 +19,9 @@ export const registerMarkAsResolvedRoute = ( router.post( { path: '/mark_as_resolved', + options: { + access: 'internal', + }, validate: { body: schema.object({ domainId: schema.string(), diff --git a/packages/core/feature-flags/README.mdx b/packages/core/feature-flags/README.mdx index 99e10b72aa68..8a28fdf35932 100644 --- a/packages/core/feature-flags/README.mdx +++ b/packages/core/feature-flags/README.mdx @@ -15,7 +15,7 @@ The service is always enabled, however, it will return the fallback value if a f Kibana only registers a provider when running on Elastic Cloud Hosted/Serverless. And even in those scenarios, we expect that some customers might have network restrictions that might not allow the flags to evaluate. The fallback value must provide a non-broken experience to users. -:warning: Feature Flags are considered dynamic configuration and cannot be used for settings that require restarting Kibana. +⚠️Feature Flags are considered dynamic configuration and cannot be used for settings that require restarting Kibana. One example of invalid use cases are settings used during the `setup` lifecycle of the plugin, such as settings that define if an HTTP route is registered or not. Instead, you should always register the route, and return `404 - Not found` in the route handler if the feature flag returns a _disabled_ state. diff --git a/packages/core/feature-flags/core-feature-flags-browser-internal/src/feature_flags_service.ts b/packages/core/feature-flags/core-feature-flags-browser-internal/src/feature_flags_service.ts index e282cc52ddd4..afc32d93aee3 100644 --- a/packages/core/feature-flags/core-feature-flags-browser-internal/src/feature_flags_service.ts +++ b/packages/core/feature-flags/core-feature-flags-browser-internal/src/feature_flags_service.ts @@ -68,7 +68,15 @@ export class FeatureFlagsService { if (this.isProviderReadyPromise) { throw new Error('A provider has already been set. This API cannot be called twice.'); } + const transaction = apm.startTransaction('set-provider', 'feature-flags'); this.isProviderReadyPromise = OpenFeature.setProviderAndWait(provider); + this.isProviderReadyPromise + .then(() => transaction?.end()) + .catch((err) => { + this.logger.error(err); + apm.captureError(err); + transaction?.end(); + }); }, appendContext: (contextToAppend) => this.appendContext(contextToAppend), }; diff --git a/packages/core/http/core-http-router-server-internal/src/request.ts b/packages/core/http/core-http-router-server-internal/src/request.ts index 9f89f1a70bb4..cbccf31fc094 100644 --- a/packages/core/http/core-http-router-server-internal/src/request.ts +++ b/packages/core/http/core-http-router-server-internal/src/request.ts @@ -177,9 +177,14 @@ export class CoreKibanaRequest< this.headers = isRealReq ? deepFreeze({ ...request.headers }) : request.headers; this.isSystemRequest = this.headers['kbn-system-request'] === 'true'; this.isFakeRequest = !isRealReq; + // set to false if elasticInternalOrigin is explicitly set to false + // otherwise check for the header or the query param this.isInternalApiRequest = - X_ELASTIC_INTERNAL_ORIGIN_REQUEST in this.headers || - Boolean(this.url?.searchParams?.has(ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM)); + this.url?.searchParams?.get(ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM) === 'false' + ? false + : X_ELASTIC_INTERNAL_ORIGIN_REQUEST in this.headers || + this.url?.searchParams?.has(ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM); + // prevent Symbol exposure via Object.getOwnPropertySymbols() Object.defineProperty(this, requestSymbol, { value: request, diff --git a/packages/core/http/core-http-router-server-internal/src/router.ts b/packages/core/http/core-http-router-server-internal/src/router.ts index e7ad85fcda33..c2ea09605c4e 100644 --- a/packages/core/http/core-http-router-server-internal/src/router.ts +++ b/packages/core/http/core-http-router-server-internal/src/router.ts @@ -28,12 +28,12 @@ import type { VersionedRouter, RouteRegistrar, RouteSecurity, + PostValidationMetadata, } from '@kbn/core-http-server'; import { isZod } from '@kbn/zod'; import { validBodyOutput, getRequestValidation } from '@kbn/core-http-server'; import type { RouteSecurityGetter } from '@kbn/core-http-server'; import type { DeepPartial } from '@kbn/utility-types'; -import { RouteDeprecationInfo } from '@kbn/core-http-server/src/router/route'; import { RouteValidator } from './validator'; import { ALLOWED_PUBLIC_VERSION, CoreVersionedRouter } from './versioned_router'; import { CoreKibanaRequest } from './request'; @@ -287,10 +287,13 @@ export class Router { const postValidate: RouterEvents = 'onPostValidate'; - Router.ee.emit(postValidate, request, routeOptions); + Router.ee.emit(postValidate, request, postValidateConext); }; private async handle({ @@ -304,7 +307,7 @@ export class Router void; + onPostValidation: (req: KibanaRequest, metadata: PostValidationMetadata) => void; }; isPublicUnversionedRoute: boolean; handler: RequestHandlerEnhanced< @@ -337,11 +340,19 @@ export class Router { + const access = route.options.access; if (route.isVersioned === true) { return [...route.handlers.entries()].map(([_, { options }]) => { const deprecated = options.options?.deprecated; - return { route, version: `${options.version}`, deprecated }; + return { route, version: `${options.version}`, deprecated, access }; }); } - return { route, version: undefined, deprecated: route.options.deprecated }; + + return { route, version: undefined, deprecated: route.options.deprecated, access }; }) .flat() - .filter(({ deprecated }) => isObject(deprecated)) - .flatMap(({ route, deprecated, version }) => { + .filter(({ deprecated, access }) => { + const isRouteDeprecation = isObject(deprecated); + const isAccessDeprecation = access === 'internal'; + return isRouteDeprecation || isAccessDeprecation; + }) + .flatMap(({ route, deprecated, version, access }) => { return { routeDeprecationOptions: deprecated!, routeMethod: route.method as RouteMethod, routePath: route.path, routeVersion: version, + routeAccess: access, }; }) ); diff --git a/packages/core/http/core-http-server-internal/src/lifecycle_handlers.test.ts b/packages/core/http/core-http-server-internal/src/lifecycle_handlers.test.ts index c81816470885..28f8c70ebbb1 100644 --- a/packages/core/http/core-http-server-internal/src/lifecycle_handlers.test.ts +++ b/packages/core/http/core-http-server-internal/src/lifecycle_handlers.test.ts @@ -417,6 +417,33 @@ describe('restrictInternal post-auth handler', () => { const request = createForgeRequest('public', { 'x-elastic-internal-origin': 'Kibana' }); createForwardSuccess(handler, request); }); + + it('overrides internal api when elasticInternalOrigin=false is set explicitly', () => { + const handler = createRestrictInternalRoutesPostAuthHandler( + { ...config, restrictInternalApis: true }, + logger + ); + + // Will be treated as external + const request = createForgeRequest( + 'internal', + { 'x-elastic-internal-origin': 'Kibana' }, + { elasticInternalOrigin: 'false' } + ); + + responseFactory.badRequest.mockReturnValue('badRequest' as any); + + const result = handler(request, responseFactory, toolkit); + + expect(toolkit.next).not.toHaveBeenCalled(); + expect(responseFactory.badRequest).toHaveBeenCalledTimes(1); + expect(responseFactory.badRequest.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "body": "uri [/internal/some-path] with method [get] exists but is not available with the current configuration", + } + `); + expect(result).toEqual('badRequest'); + }); }); describe('customHeaders pre-response handler', () => { diff --git a/packages/core/http/core-http-server-internal/src/types.ts b/packages/core/http/core-http-server-internal/src/types.ts index 0706af9ad73a..c0443e5bc049 100644 --- a/packages/core/http/core-http-server-internal/src/types.ts +++ b/packages/core/http/core-http-server-internal/src/types.ts @@ -16,10 +16,10 @@ import type { IContextContainer, HttpServiceSetup, HttpServiceStart, - RouterDeprecatedRouteDetails, + RouterDeprecatedApiDetails, } from '@kbn/core-http-server'; -import { CoreKibanaRequest } from '@kbn/core-http-router-server-internal'; -import { RouteDeprecationInfo } from '@kbn/core-http-server/src/router/route'; +import type { CoreKibanaRequest } from '@kbn/core-http-router-server-internal'; +import type { PostValidationMetadata } from '@kbn/core-http-server'; import type { HttpServerSetup } from './http_server'; import type { ExternalUrlConfig } from './external_url'; import type { InternalStaticAssets } from './static_assets'; @@ -58,7 +58,7 @@ export interface InternalHttpServiceSetup plugin?: PluginOpaqueId ) => IRouter; registerOnPostValidation( - cb: (req: CoreKibanaRequest, metadata: { deprecated: RouteDeprecationInfo }) => void + cb: (req: CoreKibanaRequest, metadata: PostValidationMetadata) => void ): void; registerRouterAfterListening: (router: IRouter) => void; registerStaticDir: (path: string, dirPath: string) => void; @@ -71,7 +71,7 @@ export interface InternalHttpServiceSetup contextName: ContextName, provider: IContextProvider ) => IContextContainer; - getRegisteredDeprecatedApis: () => RouterDeprecatedRouteDetails[]; + getRegisteredDeprecatedApis: () => RouterDeprecatedApiDetails[]; } /** @internal */ diff --git a/packages/core/http/core-http-server/index.ts b/packages/core/http/core-http-server/index.ts index 9c12f6a09ac4..7b79dfe313bd 100644 --- a/packages/core/http/core-http-server/index.ts +++ b/packages/core/http/core-http-server/index.ts @@ -93,7 +93,9 @@ export type { IRouter, RouteRegistrar, RouterRoute, - RouterDeprecatedRouteDetails, + RouterDeprecatedApiDetails, + RouterAccessDeprecatedApiDetails, + RouterRouteDeprecatedApiDetails, IKibanaSocket, KibanaErrorResponseFactory, KibanaRedirectionResponseFactory, @@ -120,6 +122,8 @@ export type { RouteSecurity, RouteSecurityGetter, InternalRouteSecurity, + RouteDeprecationInfo, + PostValidationMetadata, } from './src/router'; export { validBodyOutput, diff --git a/packages/core/http/core-http-server/src/http_contract.ts b/packages/core/http/core-http-server/src/http_contract.ts index e2f675bd8d0c..2da699e5ea4a 100644 --- a/packages/core/http/core-http-server/src/http_contract.ts +++ b/packages/core/http/core-http-server/src/http_contract.ts @@ -12,7 +12,7 @@ import type { IContextProvider, IRouter, RequestHandlerContextBase, - RouterDeprecatedRouteDetails, + RouterDeprecatedApiDetails, } from './router'; import type { AuthenticationHandler, @@ -362,12 +362,12 @@ export interface HttpServiceSetup< getServerInfo: () => HttpServerInfo; /** - * Provides a list of all registered deprecated routes {{@link RouterDeprecatedRouteDetails | information}}. + * Provides a list of all registered deprecated routes {{@link RouterDeprecatedApiDetails | information}}. * The routers will be evaluated everytime this function gets called to * accommodate for any late route registrations - * @returns {RouterDeprecatedRouteDetails[]} + * @returns {RouterDeprecatedApiDetails[]} */ - getDeprecatedRoutes: () => RouterDeprecatedRouteDetails[]; + getDeprecatedRoutes: () => RouterDeprecatedApiDetails[]; } /** @public */ diff --git a/packages/core/http/core-http-server/src/router/index.ts b/packages/core/http/core-http-server/src/router/index.ts index 8e2b9373c43b..166fcad32495 100644 --- a/packages/core/http/core-http-server/src/router/index.ts +++ b/packages/core/http/core-http-server/src/router/index.ts @@ -64,6 +64,8 @@ export type { RouteSecurity, Privilege, PrivilegeSet, + RouteDeprecationInfo, + PostValidationMetadata, } from './route'; export { validBodyOutput, ReservedPrivilegesSet } from './route'; @@ -80,7 +82,14 @@ export type { LazyValidator, } from './route_validator'; export { RouteValidationError } from './route_validator'; -export type { IRouter, RouteRegistrar, RouterRoute, RouterDeprecatedRouteDetails } from './router'; +export type { + IRouter, + RouteRegistrar, + RouterRoute, + RouterDeprecatedApiDetails, + RouterAccessDeprecatedApiDetails, + RouterRouteDeprecatedApiDetails, +} from './router'; export type { IKibanaSocket } from './socket'; export type { KibanaErrorResponseFactory, diff --git a/packages/core/http/core-http-server/src/router/route.ts b/packages/core/http/core-http-server/src/router/route.ts index eec9a01f6056..da24adcb6802 100644 --- a/packages/core/http/core-http-server/src/router/route.ts +++ b/packages/core/http/core-http-server/src/router/route.ts @@ -525,3 +525,12 @@ export interface RouteConfig { */ options?: RouteConfigOptions; } + +/** + * Post Validation Route emitter metadata. + */ +export interface PostValidationMetadata { + deprecated?: RouteDeprecationInfo; + isInternalApiRequest: boolean; + isPublicAccess: boolean; +} diff --git a/packages/core/http/core-http-server/src/router/router.ts b/packages/core/http/core-http-server/src/router/router.ts index d8b79bee1302..f770cfcc45e4 100644 --- a/packages/core/http/core-http-server/src/router/router.ts +++ b/packages/core/http/core-http-server/src/router/router.ts @@ -10,7 +10,7 @@ import type { Request, ResponseObject, ResponseToolkit } from '@hapi/hapi'; import type Boom from '@hapi/boom'; import type { VersionedRouter } from '../versioning'; -import type { RouteConfig, RouteDeprecationInfo, RouteMethod } from './route'; +import type { RouteAccess, RouteConfig, RouteDeprecationInfo, RouteMethod } from './route'; import type { RequestHandler, RequestHandlerWrapper } from './request_handler'; import type { RequestHandlerContextBase } from './request_handler_context'; import type { RouteConfigOptions } from './route'; @@ -143,9 +143,22 @@ export interface RouterRoute { } /** @public */ -export interface RouterDeprecatedRouteDetails { - routeDeprecationOptions: RouteDeprecationInfo; +export interface RouterDeprecatedApiDetails { + routeDeprecationOptions?: RouteDeprecationInfo; routeMethod: RouteMethod; routePath: string; routeVersion?: string; + routeAccess?: RouteAccess; +} + +/** @public */ +export interface RouterRouteDeprecatedApiDetails extends RouterDeprecatedApiDetails { + routeAccess: 'public'; + routeDeprecationOptions: RouteDeprecationInfo; +} + +/** @public */ +export interface RouterAccessDeprecatedApiDetails extends RouterDeprecatedApiDetails { + routeAccess: 'internal'; + routeDeprecationOptions?: RouteDeprecationInfo; } diff --git a/packages/core/root/core-root-server-internal/src/server.ts b/packages/core/root/core-root-server-internal/src/server.ts index 5082a27930e8..d38a52b73494 100644 --- a/packages/core/root/core-root-server-internal/src/server.ts +++ b/packages/core/root/core-root-server-internal/src/server.ts @@ -309,6 +309,7 @@ export class Server { elasticsearch: elasticsearchServiceSetup, deprecations: deprecationsSetup, coreUsageData: coreUsageDataSetup, + docLinks: docLinksSetup, }); const uiSettingsSetup = await this.uiSettings.setup({ diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.test.ts index 1aeabb7e86de..c84b30cf1577 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/actions/catch_retryable_es_client_errors.test.ts @@ -72,24 +72,25 @@ describe('catchRetryableEsClientErrors', () => { type: 'retryable_es_client_error', }); }); - it('ResponseError with retryable status code', async () => { - const statusCodes = [503, 401, 403, 408, 410, 429]; - return Promise.all( - statusCodes.map(async (status) => { - const error = new esErrors.ResponseError( - elasticsearchClientMock.createApiResponse({ - statusCode: status, - body: { error: { type: 'reason' } }, - }) - ); - expect( - ((await Promise.reject(error).catch(catchRetryableEsClientErrors)) as any).left - ).toMatchObject({ - message: 'reason', - type: 'retryable_es_client_error', - }); - }) - ); - }); + it.each([503, 401, 403, 408, 410, 429])( + 'ResponseError with retryable status code (%d)', + async (status) => { + const error = new esErrors.ResponseError( + elasticsearchClientMock.createApiResponse({ + statusCode: status, + body: { error: { type: 'reason' } }, + }) + ); + expect( + ((await Promise.reject(error).catch(catchRetryableEsClientErrors)) as any).left + ).toMatchObject({ + message: + status === 410 + ? 'This API is unavailable in the version of Elasticsearch you are using.' + : 'reason', + type: 'retryable_es_client_error', + }); + } + ); }); }); diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_create.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_create.ts index c9a8656b3f75..c0df8b57094e 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_create.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_create.ts @@ -8,7 +8,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { RouteAccess } from '@kbn/core-http-server'; +import type { RouteAccess, RouteDeprecationInfo } from '@kbn/core-http-server'; import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal'; import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; import type { Logger } from '@kbn/logging'; @@ -24,11 +24,12 @@ interface RouteDependencies { coreUsageData: InternalCoreUsageDataSetup; logger: Logger; access: RouteAccess; + deprecationInfo: RouteDeprecationInfo; } export const registerBulkCreateRoute = ( router: InternalSavedObjectRouter, - { config, coreUsageData, logger, access }: RouteDependencies + { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies ) => { const { allowHttpApiAccess } = config; router.post( @@ -38,8 +39,7 @@ export const registerBulkCreateRoute = ( summary: `Create saved objects`, tags: ['oas-tag:saved objects'], access, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: deprecationInfo, }, validate: { query: schema.object({ diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_delete.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_delete.ts index 65209a607274..21ea532cae17 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_delete.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_delete.ts @@ -8,7 +8,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { RouteAccess } from '@kbn/core-http-server'; +import type { RouteAccess, RouteDeprecationInfo } from '@kbn/core-http-server'; import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal'; import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; import type { Logger } from '@kbn/logging'; @@ -24,11 +24,12 @@ interface RouteDependencies { coreUsageData: InternalCoreUsageDataSetup; logger: Logger; access: RouteAccess; + deprecationInfo: RouteDeprecationInfo; } export const registerBulkDeleteRoute = ( router: InternalSavedObjectRouter, - { config, coreUsageData, logger, access }: RouteDependencies + { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies ) => { const { allowHttpApiAccess } = config; router.post( @@ -38,8 +39,7 @@ export const registerBulkDeleteRoute = ( summary: `Delete saved objects`, tags: ['oas-tag:saved objects'], access, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: deprecationInfo, }, validate: { body: schema.arrayOf( diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_get.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_get.ts index 3f87ca12248a..1a97377f872f 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_get.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_get.ts @@ -8,7 +8,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { RouteAccess } from '@kbn/core-http-server'; +import type { RouteAccess, RouteDeprecationInfo } from '@kbn/core-http-server'; import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal'; import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; import type { Logger } from '@kbn/logging'; @@ -24,11 +24,12 @@ interface RouteDependencies { coreUsageData: InternalCoreUsageDataSetup; logger: Logger; access: RouteAccess; + deprecationInfo: RouteDeprecationInfo; } export const registerBulkGetRoute = ( router: InternalSavedObjectRouter, - { config, coreUsageData, logger, access }: RouteDependencies + { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies ) => { const { allowHttpApiAccess } = config; router.post( @@ -38,8 +39,7 @@ export const registerBulkGetRoute = ( summary: `Get saved objects`, tags: ['oas-tag:saved objects'], access, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: deprecationInfo, }, validate: { body: schema.arrayOf( diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_resolve.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_resolve.ts index 8e19114e798e..b464e06ac15c 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_resolve.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_resolve.ts @@ -8,7 +8,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { RouteAccess } from '@kbn/core-http-server'; +import type { RouteAccess, RouteDeprecationInfo } from '@kbn/core-http-server'; import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal'; import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; import type { Logger } from '@kbn/logging'; @@ -24,11 +24,12 @@ interface RouteDependencies { coreUsageData: InternalCoreUsageDataSetup; logger: Logger; access: RouteAccess; + deprecationInfo: RouteDeprecationInfo; } export const registerBulkResolveRoute = ( router: InternalSavedObjectRouter, - { config, coreUsageData, logger, access }: RouteDependencies + { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies ) => { const { allowHttpApiAccess } = config; router.post( @@ -38,8 +39,7 @@ export const registerBulkResolveRoute = ( summary: `Resolve saved objects`, tags: ['oas-tag:saved objects'], access, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: deprecationInfo, description: `Retrieve multiple Kibana saved objects by ID, using any legacy URL aliases if they exist. Under certain circumstances, when Kibana is upgraded, saved object migrations may necessitate regenerating some object IDs to enable new features. When an object's ID is regenerated, a legacy URL alias is created for that object, preserving its old ID. In such a scenario, that object can be retrieved with the bulk resolve API using either its new ID or its old ID.`, }, diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_update.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_update.ts index 825a5f95482c..7793484e0181 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_update.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/bulk_update.ts @@ -8,7 +8,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { RouteAccess } from '@kbn/core-http-server'; +import type { RouteAccess, RouteDeprecationInfo } from '@kbn/core-http-server'; import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal'; import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; import type { Logger } from '@kbn/logging'; @@ -24,11 +24,12 @@ interface RouteDependencies { coreUsageData: InternalCoreUsageDataSetup; logger: Logger; access: RouteAccess; + deprecationInfo: RouteDeprecationInfo; } export const registerBulkUpdateRoute = ( router: InternalSavedObjectRouter, - { config, coreUsageData, logger, access }: RouteDependencies + { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies ) => { const { allowHttpApiAccess } = config; router.put( @@ -38,8 +39,7 @@ export const registerBulkUpdateRoute = ( summary: `Update saved objects`, tags: ['oas-tag:saved objects'], access, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: deprecationInfo, }, validate: { body: schema.arrayOf( diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/create.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/create.ts index 57f4a10ed937..4b6a58b107f1 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/create.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/create.ts @@ -8,7 +8,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { RouteAccess } from '@kbn/core-http-server'; +import type { RouteAccess, RouteDeprecationInfo } from '@kbn/core-http-server'; import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal'; import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; import type { Logger } from '@kbn/logging'; @@ -24,11 +24,12 @@ interface RouteDependencies { coreUsageData: InternalCoreUsageDataSetup; logger: Logger; access: RouteAccess; + deprecationInfo: RouteDeprecationInfo; } export const registerCreateRoute = ( router: InternalSavedObjectRouter, - { config, coreUsageData, logger, access }: RouteDependencies + { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies ) => { const { allowHttpApiAccess } = config; router.post( @@ -38,8 +39,7 @@ export const registerCreateRoute = ( summary: `Create a saved object`, tags: ['oas-tag:saved objects'], access, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: deprecationInfo, }, validate: { params: schema.object({ diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/delete.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/delete.ts index 69287821d804..b3e1bdab6da4 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/delete.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/delete.ts @@ -8,7 +8,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { RouteAccess } from '@kbn/core-http-server'; +import type { RouteAccess, RouteDeprecationInfo } from '@kbn/core-http-server'; import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal'; import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; import type { Logger } from '@kbn/logging'; @@ -24,11 +24,12 @@ interface RouteDependencies { coreUsageData: InternalCoreUsageDataSetup; logger: Logger; access: RouteAccess; + deprecationInfo: RouteDeprecationInfo; } export const registerDeleteRoute = ( router: InternalSavedObjectRouter, - { config, coreUsageData, logger, access }: RouteDependencies + { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies ) => { const { allowHttpApiAccess } = config; router.delete( @@ -38,8 +39,7 @@ export const registerDeleteRoute = ( summary: `Delete a saved object`, tags: ['oas-tag:saved objects'], access, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: deprecationInfo, }, validate: { params: schema.object({ diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/find.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/find.ts index 884ba1ed5c42..534d765080be 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/find.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/find.ts @@ -8,7 +8,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { RouteAccess } from '@kbn/core-http-server'; +import type { RouteAccess, RouteDeprecationInfo } from '@kbn/core-http-server'; import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal'; import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; import type { Logger } from '@kbn/logging'; @@ -21,11 +21,12 @@ interface RouteDependencies { coreUsageData: InternalCoreUsageDataSetup; logger: Logger; access: RouteAccess; + deprecationInfo: RouteDeprecationInfo; } export const registerFindRoute = ( router: InternalSavedObjectRouter, - { config, coreUsageData, logger, access }: RouteDependencies + { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies ) => { const referenceSchema = schema.object({ type: schema.string(), @@ -42,8 +43,7 @@ export const registerFindRoute = ( summary: `Search for saved objects`, tags: ['oas-tag:saved objects'], access, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: deprecationInfo, }, validate: { query: schema.object({ diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/get.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/get.ts index 9fe3aa8ff20c..12c9c774ae7b 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/get.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/get.ts @@ -8,7 +8,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { RouteAccess } from '@kbn/core-http-server'; +import type { RouteAccess, RouteDeprecationInfo } from '@kbn/core-http-server'; import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal'; import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; import type { Logger } from '@kbn/logging'; @@ -24,11 +24,12 @@ interface RouteDependencies { coreUsageData: InternalCoreUsageDataSetup; logger: Logger; access: RouteAccess; + deprecationInfo: RouteDeprecationInfo; } export const registerGetRoute = ( router: InternalSavedObjectRouter, - { config, coreUsageData, logger, access }: RouteDependencies + { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies ) => { const { allowHttpApiAccess } = config; router.get( @@ -38,8 +39,7 @@ export const registerGetRoute = ( summary: `Get a saved object`, tags: ['oas-tag:saved objects'], access, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: deprecationInfo, }, validate: { params: schema.object({ diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/index.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/index.ts index 48ac75e04514..a9a83d55a0da 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/index.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/index.ts @@ -14,6 +14,8 @@ import type { IKibanaMigrator, } from '@kbn/core-saved-objects-base-server-internal'; import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; +import { DocLinksServiceSetup } from '@kbn/core-doc-links-server'; +import { RouteDeprecationInfo } from '@kbn/core-http-server'; import type { InternalSavedObjectsRequestHandlerContext } from '../internal_types'; import { registerGetRoute } from './get'; import { registerResolveRoute } from './resolve'; @@ -43,6 +45,7 @@ export function registerRoutes({ kibanaVersion, kibanaIndex, isServerless, + docLinks, }: { http: InternalHttpServiceSetup; coreUsageData: InternalCoreUsageDataSetup; @@ -52,28 +55,105 @@ export function registerRoutes({ kibanaVersion: string; kibanaIndex: string; isServerless: boolean; + docLinks: DocLinksServiceSetup; }) { const router = http.createRouter('/api/saved_objects/'); const internalOnServerless = isServerless ? 'internal' : 'public'; + const deprecationInfo: RouteDeprecationInfo = { + documentationUrl: `${docLinks.links.management.savedObjectsApiList}`, + severity: 'warning' as const, // will not break deployment upon upgrade + reason: { + type: 'deprecate' as const, + }, + }; - registerGetRoute(router, { config, coreUsageData, logger, access: internalOnServerless }); - registerResolveRoute(router, { config, coreUsageData, logger, access: internalOnServerless }); + const legacyDeprecationInfo = { + documentationUrl: `${docLinks.links.kibana.dashboardImportExport}`, + severity: 'warning' as const, // will not break deployment upon upgrade + reason: { + type: 'remove' as const, // no alternative for posting `.json`, requires file format change to `.ndjson` + }, + }; + + registerGetRoute(router, { + config, + coreUsageData, + logger, + access: internalOnServerless, + deprecationInfo, + }); + registerResolveRoute(router, { + config, + coreUsageData, + logger, + access: internalOnServerless, + deprecationInfo, + }); registerCreateRoute(router, { config, coreUsageData, logger, access: internalOnServerless, + deprecationInfo, + }); + registerDeleteRoute(router, { + config, + coreUsageData, + logger, + access: internalOnServerless, + deprecationInfo, + }); + registerFindRoute(router, { + config, + coreUsageData, + logger, + access: internalOnServerless, + deprecationInfo, + }); + registerUpdateRoute(router, { + config, + coreUsageData, + logger, + access: internalOnServerless, + deprecationInfo, + }); + registerBulkGetRoute(router, { + config, + coreUsageData, + logger, + access: internalOnServerless, + deprecationInfo, + }); + registerBulkCreateRoute(router, { + config, + coreUsageData, + logger, + access: internalOnServerless, + deprecationInfo, + }); + registerBulkResolveRoute(router, { + config, + coreUsageData, + logger, + access: internalOnServerless, + deprecationInfo, + }); + registerBulkUpdateRoute(router, { + config, + coreUsageData, + logger, + access: internalOnServerless, + deprecationInfo, + }); + registerBulkDeleteRoute(router, { + config, + coreUsageData, + logger, + access: internalOnServerless, + deprecationInfo, }); - registerDeleteRoute(router, { config, coreUsageData, logger, access: internalOnServerless }); - registerFindRoute(router, { config, coreUsageData, logger, access: internalOnServerless }); - registerUpdateRoute(router, { config, coreUsageData, logger, access: internalOnServerless }); - registerBulkGetRoute(router, { config, coreUsageData, logger, access: internalOnServerless }); - registerBulkCreateRoute(router, { config, coreUsageData, logger, access: internalOnServerless }); - registerBulkResolveRoute(router, { config, coreUsageData, logger, access: internalOnServerless }); - registerBulkUpdateRoute(router, { config, coreUsageData, logger, access: internalOnServerless }); - registerBulkDeleteRoute(router, { config, coreUsageData, logger, access: internalOnServerless }); registerExportRoute(router, { config, coreUsageData }); registerImportRoute(router, { config, coreUsageData }); @@ -85,12 +165,14 @@ export function registerRoutes({ coreUsageData, logger, access: internalOnServerless, + legacyDeprecationInfo, }); registerLegacyExportRoute(legacyRouter, { kibanaVersion, coreUsageData, logger, access: internalOnServerless, + legacyDeprecationInfo, }); const internalRouter = http.createRouter( diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/export.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/export.ts index f3cf776f7d97..6da4acf798e1 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/export.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/export.ts @@ -11,7 +11,7 @@ import moment from 'moment'; import { schema } from '@kbn/config-schema'; import type { Logger } from '@kbn/logging'; import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; -import type { RouteAccess } from '@kbn/core-http-server'; +import type { RouteAccess, RouteDeprecationInfo } from '@kbn/core-http-server'; import type { InternalSavedObjectRouter } from '../../internal_types'; import { exportDashboards } from './lib'; @@ -22,11 +22,13 @@ export const registerLegacyExportRoute = ( coreUsageData, logger, access, + legacyDeprecationInfo, }: { kibanaVersion: string; coreUsageData: InternalCoreUsageDataSetup; logger: Logger; access: RouteAccess; + legacyDeprecationInfo: RouteDeprecationInfo; } ) => { router.get( @@ -39,6 +41,7 @@ export const registerLegacyExportRoute = ( }, options: { access, + deprecated: legacyDeprecationInfo, tags: ['api'], }, }, diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/import.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/import.ts index e45ef3205af1..ad205bf65f84 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/import.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/import.ts @@ -11,7 +11,7 @@ import { schema } from '@kbn/config-schema'; import type { Logger } from '@kbn/logging'; import type { SavedObject } from '@kbn/core-saved-objects-server'; import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; -import type { RouteAccess } from '@kbn/core-http-server'; +import type { RouteAccess, RouteDeprecationInfo } from '@kbn/core-http-server'; import type { InternalSavedObjectRouter } from '../../internal_types'; import { importDashboards } from './lib'; @@ -22,11 +22,13 @@ export const registerLegacyImportRoute = ( coreUsageData, logger, access, + legacyDeprecationInfo, }: { maxImportPayloadBytes: number; coreUsageData: InternalCoreUsageDataSetup; logger: Logger; access: RouteAccess; + legacyDeprecationInfo: RouteDeprecationInfo; } ) => { router.post( @@ -50,6 +52,7 @@ export const registerLegacyImportRoute = ( body: { maxBytes: maxImportPayloadBytes, }, + deprecated: legacyDeprecationInfo, }, }, async (context, request, response) => { diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/resolve.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/resolve.ts index 28a6c82e9ffd..debbacbb0633 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/resolve.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/resolve.ts @@ -8,7 +8,7 @@ */ import { schema } from '@kbn/config-schema'; -import type { RouteAccess } from '@kbn/core-http-server'; +import type { RouteAccess, RouteDeprecationInfo } from '@kbn/core-http-server'; import { SavedObjectConfig } from '@kbn/core-saved-objects-base-server-internal'; import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; import type { Logger } from '@kbn/logging'; @@ -20,11 +20,12 @@ interface RouteDependencies { coreUsageData: InternalCoreUsageDataSetup; logger: Logger; access: RouteAccess; + deprecationInfo: RouteDeprecationInfo; } export const registerResolveRoute = ( router: InternalSavedObjectRouter, - { config, coreUsageData, logger, access }: RouteDependencies + { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies ) => { const { allowHttpApiAccess } = config; router.get( @@ -34,8 +35,7 @@ export const registerResolveRoute = ( summary: `Resolve a saved object`, tags: ['oas-tag:saved objects'], access, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: deprecationInfo, description: `Retrieve a single Kibana saved object by ID, using any legacy URL alias if it exists. Under certain circumstances, when Kibana is upgraded, saved object migrations may necessitate regenerating some object IDs to enable new features. When an object's ID is regenerated, a legacy URL alias is created for that object, preserving its old ID. In such a scenario, that object can be retrieved with the resolve API using either its new ID or its old ID.`, }, diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/update.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/update.ts index cfedc3ce03d2..6f372235070b 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/update.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/update.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { RouteAccess } from '@kbn/core-http-server'; +import type { RouteAccess, RouteDeprecationInfo } from '@kbn/core-http-server'; import { schema } from '@kbn/config-schema'; import type { SavedObjectsUpdateOptions } from '@kbn/core-saved-objects-api-server'; import type { Logger } from '@kbn/logging'; @@ -25,11 +25,12 @@ interface RouteDependencies { coreUsageData: InternalCoreUsageDataSetup; logger: Logger; access: RouteAccess; + deprecationInfo: RouteDeprecationInfo; } export const registerUpdateRoute = ( router: InternalSavedObjectRouter, - { config, coreUsageData, logger, access }: RouteDependencies + { config, coreUsageData, logger, access, deprecationInfo }: RouteDependencies ) => { const { allowHttpApiAccess } = config; router.put( @@ -39,8 +40,7 @@ export const registerUpdateRoute = ( summary: `Update a saved object`, tags: ['oas-tag:saved objects'], access, - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: deprecationInfo, }, validate: { params: schema.object({ diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.test.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.test.ts index 667c4a5cea91..70e8fcf17c79 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.test.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.test.ts @@ -98,6 +98,7 @@ describe('SavedObjectsService', () => { elasticsearch: elasticsearchMock, deprecations: deprecationsSetup, coreUsageData: createCoreUsageDataSetupMock(), + docLinks: docLinksServiceMock.createSetupContract(), }; }; @@ -180,6 +181,18 @@ describe('SavedObjectsService', () => { expect(registerRoutesMock).toHaveBeenCalledWith(expect.objectContaining({ kibanaVersion })); }); + it('calls registerRoutes with docLinks', async () => { + const coreContext = createCoreContext(); + const mockedLinks = docLinksServiceMock.createSetupContract(); + + const soService = new SavedObjectsService(coreContext); + await soService.setup(createSetupDeps()); + + expect(registerRoutesMock).toHaveBeenCalledWith( + expect.objectContaining({ docLinks: mockedLinks }) + ); + }); + describe('#setClientFactoryProvider', () => { it('registers the factory to the clientProvider', async () => { const coreContext = createCoreContext(); diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts index 522a8e1943a2..04be2f5929f0 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts @@ -13,7 +13,7 @@ import type { Logger } from '@kbn/logging'; import { stripVersionQualifier } from '@kbn/std'; import type { ServiceStatus } from '@kbn/core-status-common'; import type { CoreContext, CoreService } from '@kbn/core-base-server-internal'; -import type { DocLinksServiceStart } from '@kbn/core-doc-links-server'; +import type { DocLinksServiceSetup, DocLinksServiceStart } from '@kbn/core-doc-links-server'; import type { KibanaRequest } from '@kbn/core-http-server'; import type { InternalHttpServiceSetup } from '@kbn/core-http-server-internal'; import type { @@ -99,6 +99,7 @@ export interface SavedObjectsSetupDeps { elasticsearch: InternalElasticsearchServiceSetup; coreUsageData: InternalCoreUsageDataSetup; deprecations: DeprecationRegistryProvider; + docLinks: DocLinksServiceSetup; } /** @internal */ @@ -135,7 +136,7 @@ export class SavedObjectsService this.logger.debug('Setting up SavedObjects service'); this.setupDeps = setupDeps; - const { http, elasticsearch, coreUsageData, deprecations } = setupDeps; + const { http, elasticsearch, coreUsageData, deprecations, docLinks } = setupDeps; const savedObjectsConfig = await firstValueFrom( this.coreContext.configService.atPath('savedObjects') @@ -164,6 +165,7 @@ export class SavedObjectsService kibanaIndex: MAIN_SAVED_OBJECT_INDEX, kibanaVersion: this.kibanaVersion, isServerless: this.coreContext.env.packageInfo.buildFlavor === 'serverless', + docLinks, }); registerCoreObjectTypes(this.typeRegistry); diff --git a/packages/core/saved-objects/docs/openapi/bundled.json b/packages/core/saved-objects/docs/openapi/bundled.json index 5b8f30b0f34c..45cfdd7fa505 100644 --- a/packages/core/saved-objects/docs/openapi/bundled.json +++ b/packages/core/saved-objects/docs/openapi/bundled.json @@ -21,7 +21,7 @@ { "name": "saved objects", "x-displayName": "Saved objects", - "description": "Export sets of saved objects that you want to import into {kib}, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs.\n\nTo manage a specific type of saved object, use the corresponding APIs.\nFor example, use:\n\n* [Data views](../group/endpoint-data-views)\n* [Spaces](https://www.elastic.co/guide/en/kibana/current/spaces-api.html)\n* [Short URLs](https://www.elastic.co/guide/en/kibana/current/short-urls-api.html)\n\nWarning: Do not write documents directly to the `.kibana` index. When you write directly to the `.kibana` index, the data becomes corrupted and permanently breaks future Kibana versions.\n" + "description": "Export sets of saved objects that you want to import into Kibana, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs.\n\nTo manage a specific type of saved object, use the corresponding APIs.\nFor example, use:\n\n* [Data views](../group/endpoint-data-views)\n* [Spaces](https://www.elastic.co/guide/en/kibana/current/spaces-api.html)\n* [Short URLs](https://www.elastic.co/guide/en/kibana/current/short-urls-api.html)\n\nWarning: Do not write documents directly to the `.kibana` index. When you write directly to the `.kibana` index, the data becomes corrupted and permanently breaks future Kibana versions.\n" } ], "paths": { @@ -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 68c79b406c2b..9b5aad6e5495 100644 --- a/packages/core/saved-objects/docs/openapi/bundled.yaml +++ b/packages/core/saved-objects/docs/openapi/bundled.yaml @@ -14,7 +14,7 @@ tags: - name: saved objects x-displayName: Saved objects description: | - Export sets of saved objects that you want to import into {kib}, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs. + Export sets of saved objects that you want to import into Kibana, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs. To manage a specific type of saved object, use the corresponding APIs. For example, use: @@ -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: diff --git a/packages/core/saved-objects/docs/openapi/bundled_serverless.json b/packages/core/saved-objects/docs/openapi/bundled_serverless.json index fe4b832c495b..67b8a710b5bc 100644 --- a/packages/core/saved-objects/docs/openapi/bundled_serverless.json +++ b/packages/core/saved-objects/docs/openapi/bundled_serverless.json @@ -26,7 +26,7 @@ { "name": "saved objects", "x-displayName": "Saved objects", - "description": "Export sets of saved objects that you want to import into {kib}, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs.\n\nTo manage a specific type of saved object, use the corresponding APIs.\nFor example, use:\n\n[Data views](../group/endpoint-data-views)\n\nWarning: Do not write documents directly to the `.kibana` index. When you write directly to the `.kibana` index, the data becomes corrupted and permanently breaks future Kibana versions.\n" + "description": "Export sets of saved objects that you want to import into Kibana, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs.\n\nTo manage a specific type of saved object, use the corresponding APIs.\nFor example, use:\n\n[Data views](../group/endpoint-data-views)\n\nWarning: Do not write documents directly to the `.kibana` index. When you write directly to the `.kibana` index, the data becomes corrupted and permanently breaks future Kibana versions.\n" } ], "paths": { @@ -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 4517629a29a6..b874f0e32361 100644 --- a/packages/core/saved-objects/docs/openapi/bundled_serverless.yaml +++ b/packages/core/saved-objects/docs/openapi/bundled_serverless.yaml @@ -17,7 +17,7 @@ tags: - name: saved objects x-displayName: Saved objects description: | - Export sets of saved objects that you want to import into {kib}, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs. + Export sets of saved objects that you want to import into Kibana, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs. To manage a specific type of saved object, use the corresponding APIs. For example, use: diff --git a/packages/core/saved-objects/docs/openapi/entrypoint.yaml b/packages/core/saved-objects/docs/openapi/entrypoint.yaml index 5cd903998818..adb960a06dc4 100644 --- a/packages/core/saved-objects/docs/openapi/entrypoint.yaml +++ b/packages/core/saved-objects/docs/openapi/entrypoint.yaml @@ -12,8 +12,8 @@ tags: - name: saved objects x-displayName: Saved objects description: | - Export sets of saved objects that you want to import into {kib}, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs. - + Export sets of saved objects that you want to import into Kibana, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs. + To manage a specific type of saved object, use the corresponding APIs. For example, use: diff --git a/packages/core/saved-objects/docs/openapi/entrypoint_serverless.yaml b/packages/core/saved-objects/docs/openapi/entrypoint_serverless.yaml index 69c742a8d7ac..f0d0be2ccf76 100644 --- a/packages/core/saved-objects/docs/openapi/entrypoint_serverless.yaml +++ b/packages/core/saved-objects/docs/openapi/entrypoint_serverless.yaml @@ -12,8 +12,8 @@ tags: - name: saved objects x-displayName: Saved objects description: | - Export sets of saved objects that you want to import into {kib}, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs. - + Export sets of saved objects that you want to import into Kibana, resolve import errors, and rotate an encryption key for encrypted saved objects with the saved objects APIs. + To manage a specific type of saved object, use the corresponding APIs. For example, use: diff --git a/packages/core/test-helpers/core-test-helpers-kbn-server/src/create_root.ts b/packages/core/test-helpers/core-test-helpers-kbn-server/src/create_root.ts index e5c18f4781eb..d2fa6850a8bf 100644 --- a/packages/core/test-helpers/core-test-helpers-kbn-server/src/create_root.ts +++ b/packages/core/test-helpers/core-test-helpers-kbn-server/src/create_root.ts @@ -43,6 +43,22 @@ const DEFAULTS_SETTINGS = { root: { level: 'off', }, + loggers: [ + { + name: 'root', + level: 'error', + appenders: ['console'], + }, + { + name: 'elasticsearch.deprecation', + level: 'all', + appenders: ['deprecation'], + }, + ], + appenders: { + deprecation: { type: 'console', layout: { type: 'json' } }, + console: { type: 'console', layout: { type: 'pattern' } }, + }, }, plugins: {}, migrations: { skip: false }, diff --git a/packages/core/usage-data/core-usage-data-server/src/core_usage_stats.ts b/packages/core/usage-data/core-usage-data-server/src/core_usage_stats.ts index 39df9d30d19c..e713e3e905a4 100644 --- a/packages/core/usage-data/core-usage-data-server/src/core_usage_stats.ts +++ b/packages/core/usage-data/core-usage-data-server/src/core_usage_stats.ts @@ -145,6 +145,9 @@ export interface CoreUsageStats { 'savedObjectsRepository.resolvedOutcome.conflict'?: number; 'savedObjectsRepository.resolvedOutcome.notFound'?: number; 'savedObjectsRepository.resolvedOutcome.total'?: number; + // API Deprecations counters + 'deprecated_api_calls_resolved.total'?: number; + 'deprecated_api_calls.total'?: number; } /** diff --git a/packages/deeplinks/search/constants.ts b/packages/deeplinks/search/constants.ts index 9848bb0c3d42..52f7bb201388 100644 --- a/packages/deeplinks/search/constants.ts +++ b/packages/deeplinks/search/constants.ts @@ -25,3 +25,4 @@ export const SEARCH_ELASTICSEARCH = 'enterpriseSearchElasticsearch'; export const SEARCH_VECTOR_SEARCH = 'enterpriseSearchVectorSearch'; export const SEARCH_SEMANTIC_SEARCH = 'enterpriseSearchSemanticSearch'; export const SEARCH_AI_SEARCH = 'enterpriseSearchAISearch'; +export const SEARCH_INDICES_CREATE_INDEX = 'createIndex'; diff --git a/packages/deeplinks/search/deep_links.ts b/packages/deeplinks/search/deep_links.ts index 22dfb91bdff3..b23a86b3cc51 100644 --- a/packages/deeplinks/search/deep_links.ts +++ b/packages/deeplinks/search/deep_links.ts @@ -22,6 +22,7 @@ import { SEARCH_HOMEPAGE, SEARCH_INDICES_START, SEARCH_INDICES, + SEARCH_INDICES_CREATE_INDEX, SEARCH_ELASTICSEARCH, SEARCH_VECTOR_SEARCH, SEARCH_SEMANTIC_SEARCH, @@ -55,6 +56,8 @@ export type AppsearchLinkId = 'engines'; export type RelevanceLinkId = 'inferenceEndpoints'; +export type SearchIndicesLinkId = typeof SEARCH_INDICES_CREATE_INDEX; + export type DeepLinkId = | EnterpriseSearchApp | EnterpriseSearchContentApp @@ -77,4 +80,5 @@ export type DeepLinkId = | SearchElasticsearch | SearchVectorSearch | SearchSemanticSearch - | SearchAISearch; + | SearchAISearch + | `${SearchIndices}:${SearchIndicesLinkId}`; diff --git a/packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts b/packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts index 31c301591ae4..d3e393b68639 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/apm/instance.ts @@ -70,7 +70,6 @@ export class Instance extends Entity { ...this.fields, 'error.type': 'crash', 'error.exception': [{ message, ...(type ? { type } : {}) }], - 'error.grouping_name': getErrorGroupingKey(message), }); } error({ diff --git a/packages/kbn-apm-synthtrace-client/src/lib/apm/mobile_device.ts b/packages/kbn-apm-synthtrace-client/src/lib/apm/mobile_device.ts index b4dfafe22fc4..c0947f75531a 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/apm/mobile_device.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/apm/mobile_device.ts @@ -262,7 +262,6 @@ export class MobileDevice extends Entity { 'error.type': 'crash', 'error.id': generateLongIdWithSeed(message), 'error.exception': [{ message, ...{ type: 'crash' } }], - 'error.grouping_name': groupingName || message, }); } } diff --git a/packages/kbn-apm-synthtrace/src/lib/shared/base_client.ts b/packages/kbn-apm-synthtrace/src/lib/shared/base_client.ts index ed6d1b813184..7fd639331af8 100644 --- a/packages/kbn-apm-synthtrace/src/lib/shared/base_client.ts +++ b/packages/kbn-apm-synthtrace/src/lib/shared/base_client.ts @@ -55,7 +55,6 @@ export class SynthtraceEsClient { await this.client.indices.resolveIndex({ name: this.indices.join(','), expand_wildcards: ['open', 'hidden'], - // @ts-expect-error ignore_unavailable is not in the type definition, but it is accepted by es ignore_unavailable: true, }) ).indices.map((index: { name: string }) => index.name) diff --git a/packages/kbn-check-mappings-update-cli/current_fields.json b/packages/kbn-check-mappings-update-cli/current_fields.json index fa55bd4800c8..5493b8dc3bbd 100644 --- a/packages/kbn-check-mappings-update-cli/current_fields.json +++ b/packages/kbn-check-mappings-update-cli/current_fields.json @@ -1073,6 +1073,7 @@ "urls" ], "synthetics-param": [], + "synthetics-private-location": [], "synthetics-privates-locations": [], "tag": [ "color", diff --git a/packages/kbn-check-mappings-update-cli/current_mappings.json b/packages/kbn-check-mappings-update-cli/current_mappings.json index 9f94d36af50f..726b6e9e1d4c 100644 --- a/packages/kbn-check-mappings-update-cli/current_mappings.json +++ b/packages/kbn-check-mappings-update-cli/current_mappings.json @@ -3552,6 +3552,10 @@ "dynamic": false, "properties": {} }, + "synthetics-private-location": { + "dynamic": false, + "properties": {} + }, "synthetics-privates-locations": { "dynamic": false, "properties": {} diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index 1294f72b9f20..251d08dde715 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -40,16 +40,14 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D const WORKPLACE_SEARCH_DOCS = `${ELASTIC_WEBSITE_URL}guide/en/workplace-search/${DOC_LINK_VERSION}/`; const SEARCH_UI_DOCS = `${DOCS_WEBSITE_URL}search-ui/`; const MACHINE_LEARNING_DOCS = `${ELASTIC_WEBSITE_URL}guide/en/machine-learning/${DOC_LINK_VERSION}/`; - const SERVERLESS_DOCS = `${DOCS_WEBSITE_URL}serverless/`; - const SERVERLESS_ELASTICSEARCH_DOCS = `${SERVERLESS_DOCS}elasticsearch/`; - const SERVERLESS_OBSERVABILITY_DOCS = `${SERVERLESS_DOCS}observability/`; + const SERVERLESS_DOCS = `${ELASTIC_WEBSITE_URL}guide/en/serverless/current/`; const SEARCH_LABS_REPO = `${ELASTIC_GITHUB}elasticsearch-labs/`; const isServerless = buildFlavor === 'serverless'; return deepFreeze({ settings: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/settings.html`, elasticStackGetStarted: isServerless - ? `${SERVERLESS_DOCS}` + ? `${SERVERLESS_DOCS}intro.html` : `${ELASTIC_WEBSITE_URL}guide/en/index.html`, apiReference: `${ELASTIC_WEBSITE_URL}guide/en/starting-with-the-elasticsearch-platform-and-its-solutions/current/api-reference.html`, upgrade: { @@ -59,25 +57,25 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D apm: { kibanaSettings: `${KIBANA_DOCS}apm-settings-in-kibana.html`, supportedServiceMaps: isServerless - ? `${SERVERLESS_DOCS}apm-service-map#supported-apm-agents` + ? `${SERVERLESS_DOCS}observability-apm-service-map.html#observability-apm-service-map-supported-apm-agents` : `${KIBANA_DOCS}service-maps.html#service-maps-supported`, customLinks: isServerless - ? `${SERVERLESS_DOCS}apm-create-custom-links` + ? `${SERVERLESS_DOCS}observability-apm-create-custom-links.html` : `${KIBANA_DOCS}custom-links.html`, droppedTransactionSpans: `${APM_DOCS}guide/${DOC_LINK_VERSION}/data-model-spans.html#data-model-dropped-spans`, upgrading: `${APM_DOCS}guide/${DOC_LINK_VERSION}/upgrade.html`, metaData: `${APM_DOCS}guide/${DOC_LINK_VERSION}/data-model-metadata.html`, overview: `${APM_DOCS}guide/${DOC_LINK_VERSION}/apm-overview.html`, tailSamplingPolicies: isServerless - ? `${SERVERLESS_DOCS}apm-transaction-sampling` + ? `${SERVERLESS_DOCS}observability-apm-transaction-sampling.html` : `${OBSERVABILITY_DOCS}configure-tail-based-sampling.html`, elasticAgent: `${APM_DOCS}guide/${DOC_LINK_VERSION}/upgrade-to-apm-integration.html`, storageExplorer: `${KIBANA_DOCS}storage-explorer.html`, spanCompression: isServerless - ? `${SERVERLESS_DOCS}apm-compress-spans` + ? `${SERVERLESS_DOCS}observability-apm-compress-spans.html` : `${OBSERVABILITY_DOCS}span-compression.html`, transactionSampling: isServerless - ? `${SERVERLESS_DOCS}apm-transaction-sampling` + ? `${SERVERLESS_DOCS}observability-apm-transaction-sampling.html` : `${OBSERVABILITY_DOCS}sampling.html`, indexLifecycleManagement: `${APM_DOCS}guide/${DOC_LINK_VERSION}/ilm-how-to.html`, }, @@ -90,7 +88,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D }, console: { guide: `${KIBANA_DOCS}console-kibana.html`, - serverlessGuide: `${SERVERLESS_DOCS}devtools/run-api-requests-in-the-console`, + serverlessGuide: `${SERVERLESS_DOCS}devtools-run-api-requests-in-the-console.html`, }, dashboard: { guide: `${KIBANA_DOCS}dashboard.html`, @@ -199,7 +197,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D deployTrainedModels: `${MACHINE_LEARNING_DOCS}ml-nlp-deploy-models.html`, documentLevelSecurity: `${ELASTICSEARCH_DOCS}document-level-security.html`, e5Model: `${MACHINE_LEARNING_DOCS}ml-nlp-e5.html`, - elser: `${ELASTICSEARCH_DOCS}semantic-search-elser.html`, + elser: `${ELASTICSEARCH_DOCS}semantic-search-semantic-text.html`, engines: `${ENTERPRISE_SEARCH_DOCS}engines.html`, indexApi: `${ELASTICSEARCH_DOCS}docs-index_.html`, inferenceApiCreate: `${ELASTICSEARCH_DOCS}put-inference-api.html`, @@ -341,7 +339,9 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D luceneExpressions: `${ELASTICSEARCH_DOCS}modules-scripting-expression.html`, }, indexPatterns: { - introduction: isServerless ? `${SERVERLESS_DOCS}data-views` : `${KIBANA_DOCS}data-views.html`, + introduction: isServerless + ? `${SERVERLESS_DOCS}data-views.html` + : `${KIBANA_DOCS}data-views.html`, fieldFormattersNumber: `${KIBANA_DOCS}numeral.html`, fieldFormattersString: `${KIBANA_DOCS}managing-data-views.html#string-field-formatters`, runtimeFields: `${KIBANA_DOCS}managing-data-views.html#runtime-fields`, @@ -355,6 +355,8 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D autocompleteSuggestions: `${KIBANA_DOCS}kibana-concepts-analysts.html#autocomplete-suggestions`, secureSavedObject: `${KIBANA_DOCS}xpack-security-secure-saved-objects.html`, xpackSecurity: `${KIBANA_DOCS}xpack-security.html`, + restApis: `${KIBANA_DOCS}api.html`, + dashboardImportExport: `${KIBANA_DOCS}dashboard-api.html`, }, upgradeAssistant: { overview: `${KIBANA_DOCS}upgrade-assistant.html`, @@ -521,7 +523,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D management: { dashboardSettings: `${KIBANA_DOCS}advanced-options.html#kibana-dashboard-settings`, indexManagement: isServerless - ? `${SERVERLESS_DOCS}index-management` + ? `${SERVERLESS_DOCS}index-management.html` : `${ELASTICSEARCH_DOCS}index-mgmt.html`, kibanaSearchSettings: `${KIBANA_DOCS}advanced-options.html#kibana-search-settings`, discoverSettings: `${KIBANA_DOCS}advanced-options.html#kibana-discover-settings`, @@ -571,7 +573,9 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D nlpImportModel: `${MACHINE_LEARNING_DOCS}ml-nlp-import-model.html`, }, transforms: { - guide: isServerless ? `${SERVERLESS_DOCS}transforms` : `${ELASTICSEARCH_DOCS}transforms.html`, + guide: isServerless + ? `${SERVERLESS_DOCS}transforms.html` + : `${ELASTICSEARCH_DOCS}transforms.html`, alertingRules: `${ELASTICSEARCH_DOCS}transform-alerts.html`, }, visualize: { @@ -584,66 +588,66 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D }, observability: { guide: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}what-is-observability-serverless` + ? `${SERVERLESS_DOCS}what-is-observability-serverless.html` : `${OBSERVABILITY_DOCS}index.html`, infrastructureThreshold: `${OBSERVABILITY_DOCS}infrastructure-threshold-alert.html`, logsThreshold: `${OBSERVABILITY_DOCS}logs-threshold-alert.html`, metricsThreshold: `${OBSERVABILITY_DOCS}metrics-threshold-alert.html`, customThreshold: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}create-custom-threshold-alert-rule` + ? `${SERVERLESS_DOCS}observability-create-custom-threshold-alert-rule.html` : `${OBSERVABILITY_DOCS}custom-threshold-alert.html`, monitorStatus: `${OBSERVABILITY_DOCS}monitor-status-alert.html`, monitorUptime: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}monitor-synthetics` + ? `${SERVERLESS_DOCS}observability-monitor-synthetics.html` : `${OBSERVABILITY_DOCS}monitor-uptime.html`, tlsCertificate: `${OBSERVABILITY_DOCS}tls-certificate-alert.html`, uptimeDurationAnomaly: `${OBSERVABILITY_DOCS}duration-anomaly-alert.html`, monitorLogs: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}discover-and-explore-logs` + ? `${SERVERLESS_DOCS}observability-discover-and-explore-logs.html` : `${OBSERVABILITY_DOCS}monitor-logs.html`, analyzeMetrics: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}infrastructure-monitoring` + ? `${SERVERLESS_DOCS}observability-infrastructure-monitoring.html` : `${OBSERVABILITY_DOCS}analyze-metrics.html`, monitorUptimeSynthetics: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}monitor-synthetics` + ? `${SERVERLESS_DOCS}observability-monitor-synthetics.html` : `${OBSERVABILITY_DOCS}monitor-uptime-synthetics.html`, userExperience: `${OBSERVABILITY_DOCS}user-experience.html`, createAlerts: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}alerting` + ? `${SERVERLESS_DOCS}observability-alerting.html` : `${OBSERVABILITY_DOCS}create-alerts.html`, syntheticsAlerting: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}synthetics-settings#alerting` + ? `${SERVERLESS_DOCS}observability-synthetics-settings.html#synthetics-settings-alerting` : `${OBSERVABILITY_DOCS}synthetics-settings.html#synthetics-settings-alerting`, syntheticsCommandReference: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}synthetics-configuration#playwrightoptions` + ? `${SERVERLESS_DOCS}observability-synthetics-configuration.html#synthetics-configuration-playwright-options` : `${OBSERVABILITY_DOCS}synthetics-configuration.html#synthetics-configuration-playwright-options`, syntheticsProjectMonitors: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}synthetics-get-started-project` + ? `${SERVERLESS_DOCS}observability-synthetics-get-started-project.html` : `${OBSERVABILITY_DOCS}synthetic-run-tests.html#synthetic-monitor-choose-project`, syntheticsMigrateFromIntegration: `${OBSERVABILITY_DOCS}synthetics-migrate-from-integration.html`, sloBurnRateRule: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}create-slo-burn-rate-alert-rule` + ? `${SERVERLESS_DOCS}observability-create-slo-burn-rate-alert-rule.html` : `${OBSERVABILITY_DOCS}slo-burn-rate-alert.html`, aiAssistant: `${OBSERVABILITY_DOCS}obs-ai-assistant.html`, }, alerting: { guide: isServerless - ? `${SERVERLESS_DOCS}rules` + ? `${SERVERLESS_DOCS}rules.html` : `${KIBANA_DOCS}create-and-manage-rules.html`, actionTypes: isServerless - ? `${SERVERLESS_DOCS}action-connectors` + ? `${SERVERLESS_DOCS}action-connectors.html` : `${KIBANA_DOCS}action-types.html`, apmRulesErrorCount: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}create-error-count-threshold-alert-rule` + ? `${SERVERLESS_DOCS}observability-create-error-count-threshold-alert-rule.html` : `${KIBANA_DOCS}apm-alerts.html`, apmRulesTransactionDuration: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}create-latency-threshold-alert-rule` + ? `${SERVERLESS_DOCS}observability-create-latency-threshold-alert-rule.html` : `${KIBANA_DOCS}apm-alerts.html`, apmRulesTransactionError: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}create-failed-transaction-rate-threshold-alert-rule` + ? `${SERVERLESS_DOCS}observability-create-failed-transaction-rate-threshold-alert-rule.html` : `${KIBANA_DOCS}apm-alerts.html`, apmRulesAnomaly: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}create-anomaly-alert-rule` + ? `${SERVERLESS_DOCS}observability-create-anomaly-alert-rule.html` : `${KIBANA_DOCS}apm-alerts.html`, emailAction: `${KIBANA_DOCS}email-action-type.html`, emailActionConfig: `${KIBANA_DOCS}email-action-type.html`, @@ -654,7 +658,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D esQuery: `${KIBANA_DOCS}rule-type-es-query.html`, indexThreshold: `${KIBANA_DOCS}rule-type-index-threshold.html`, maintenanceWindows: isServerless - ? `${SERVERLESS_DOCS}maintenance-windows` + ? `${SERVERLESS_DOCS}maintenance-windows.html` : `${KIBANA_DOCS}maintenance-windows.html`, pagerDutyAction: `${KIBANA_DOCS}pagerduty-action-type.html`, preconfiguredConnectors: `${KIBANA_DOCS}pre-configured-connectors.html`, @@ -672,7 +676,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D }, maps: { connectToEms: `${KIBANA_DOCS}maps-connect-to-ems.html`, - guide: isServerless ? `${SERVERLESS_DOCS}maps` : `${KIBANA_DOCS}maps.html`, + guide: isServerless ? `${SERVERLESS_DOCS}maps.html` : `${KIBANA_DOCS}maps.html`, importGeospatialPrivileges: `${KIBANA_DOCS}import-geospatial-data.html#import-geospatial-privileges`, gdalTutorial: `${ELASTIC_WEBSITE_URL}blog/how-to-ingest-geospatial-data-into-elasticsearch-with-gdal`, termJoinsExample: `${KIBANA_DOCS}terms-join.html#_example_term_join`, @@ -814,7 +818,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D lowercase: `${ELASTICSEARCH_DOCS}lowercase-processor.html`, pipeline: `${ELASTICSEARCH_DOCS}pipeline-processor.html`, pipelines: isServerless - ? `${SERVERLESS_DOCS}ingest-pipelines` + ? `${SERVERLESS_DOCS}ingest-pipelines.html` : `${ELASTICSEARCH_DOCS}ingest.html`, csvPipelines: `${ELASTIC_WEBSITE_URL}guide/en/ecs/${ECS_VERSION}/ecs-converting.html`, pipelineFailure: `${ELASTICSEARCH_DOCS}ingest.html#handling-pipeline-failures`, @@ -862,7 +866,9 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D grantESAccessToStandaloneAgents: `${FLEET_DOCS}grant-access-to-elasticsearch.html`, upgradeElasticAgent: `${FLEET_DOCS}upgrade-elastic-agent.html`, learnMoreBlog: `${ELASTIC_WEBSITE_URL}blog/elastic-agent-and-fleet-make-it-easier-to-integrate-your-systems-with-elastic`, - apiKeysLearnMore: isServerless ? `${SERVERLESS_DOCS}api-keys` : `${KIBANA_DOCS}api-keys.html`, + apiKeysLearnMore: isServerless + ? `${SERVERLESS_DOCS}api-keys.html` + : `${KIBANA_DOCS}api-keys.html`, onPremRegistry: `${FLEET_DOCS}air-gapped.html`, packageSignatures: `${FLEET_DOCS}package-signatures.html`, secureLogstash: `${FLEET_DOCS}secure-logstash-connections.html`, @@ -947,39 +953,39 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D elasticsearch: `${SEARCH_UI_DOCS}tutorials/elasticsearch`, }, serverlessClients: { - clientLib: `${SERVERLESS_ELASTICSEARCH_DOCS}clients`, - goApiReference: `${SERVERLESS_ELASTICSEARCH_DOCS}go-client-getting-started`, - goGettingStarted: `${SERVERLESS_ELASTICSEARCH_DOCS}go-client-getting-started`, - httpApis: `${SERVERLESS_ELASTICSEARCH_DOCS}http-apis`, - httpApiReferences: `${SERVERLESS_ELASTICSEARCH_DOCS}http-apis`, - jsApiReference: `${SERVERLESS_ELASTICSEARCH_DOCS}nodejs-client-getting-started`, - jsGettingStarted: `${SERVERLESS_ELASTICSEARCH_DOCS}nodejs-client-getting-started`, - phpApiReference: `${SERVERLESS_ELASTICSEARCH_DOCS}php-client-getting-started`, - phpGettingStarted: `${SERVERLESS_ELASTICSEARCH_DOCS}php-client-getting-started`, - pythonApiReference: `${SERVERLESS_ELASTICSEARCH_DOCS}python-client-getting-started`, - pythonGettingStarted: `${SERVERLESS_ELASTICSEARCH_DOCS}python-client-getting-started`, - pythonReferences: `${SERVERLESS_ELASTICSEARCH_DOCS}python-client-getting-started`, - rubyApiReference: `${SERVERLESS_ELASTICSEARCH_DOCS}ruby-client-getting-started`, - rubyGettingStarted: `${SERVERLESS_ELASTICSEARCH_DOCS}ruby-client-getting-started`, + clientLib: `${SERVERLESS_DOCS}elasticsearch-clients.html`, + goApiReference: `${SERVERLESS_DOCS}elasticsearch-go-client-getting-started.html`, + goGettingStarted: `${SERVERLESS_DOCS}elasticsearch-go-client-getting-started.html`, + httpApis: `${SERVERLESS_DOCS}elasticsearch-http-apis.html`, + httpApiReferences: `${SERVERLESS_DOCS}elasticsearch-http-apis.html`, + jsApiReference: `${SERVERLESS_DOCS}elasticsearch-nodejs-client-getting-started.html`, + jsGettingStarted: `${SERVERLESS_DOCS}elasticsearch-nodejs-client-getting-started.html`, + phpApiReference: `${SERVERLESS_DOCS}elasticsearch-php-client-getting-started.html`, + phpGettingStarted: `${SERVERLESS_DOCS}elasticsearch-php-client-getting-started.html`, + pythonApiReference: `${SERVERLESS_DOCS}elasticsearch-python-client-getting-started.html`, + pythonGettingStarted: `${SERVERLESS_DOCS}elasticsearch-python-client-getting-started.html`, + pythonReferences: `${SERVERLESS_DOCS}elasticsearch-python-client-getting-started.html`, + rubyApiReference: `${SERVERLESS_DOCS}elasticsearch-ruby-client-getting-started.html`, + rubyGettingStarted: `${SERVERLESS_DOCS}elasticsearch-ruby-client-getting-started.html`, }, serverlessSearch: { - integrations: `${SERVERLESS_ELASTICSEARCH_DOCS}ingest-your-data`, - integrationsLogstash: `${SERVERLESS_ELASTICSEARCH_DOCS}ingest-data-through-logstash`, - integrationsBeats: `${SERVERLESS_ELASTICSEARCH_DOCS}ingest-data-through-beats`, - integrationsConnectorClient: `${SERVERLESS_ELASTICSEARCH_DOCS}ingest-data-through-integrations-connector-client`, - integrationsConnectorClientAvailableConnectors: `${SERVERLESS_ELASTICSEARCH_DOCS}ingest-data-through-integrations-connector-client#available-connectors`, - integrationsConnectorClientRunFromSource: `${SERVERLESS_ELASTICSEARCH_DOCS}ingest-data-through-integrations-connector-client#run-from-source`, - integrationsConnectorClientRunWithDocker: `${SERVERLESS_ELASTICSEARCH_DOCS}ingest-data-through-integrations-connector-client#run-with-docker`, - gettingStartedExplore: `${SERVERLESS_ELASTICSEARCH_DOCS}get-started`, - gettingStartedIngest: `${SERVERLESS_ELASTICSEARCH_DOCS}get-started`, - gettingStartedSearch: `${SERVERLESS_ELASTICSEARCH_DOCS}get-started`, + integrations: `${SERVERLESS_DOCS}elasticsearch-ingest-your-data.html`, + integrationsLogstash: `${SERVERLESS_DOCS}elasticsearch-ingest-data-through-logstash.html`, + integrationsBeats: `${SERVERLESS_DOCS}elasticsearch-ingest-data-through-beats.html`, + integrationsConnectorClient: `${SERVERLESS_DOCS}elasticsearch-ingest-data-through-integrations-connector-client.html`, + integrationsConnectorClientAvailableConnectors: `${SERVERLESS_DOCS}elasticsearch-ingest-data-through-integrations-connector-client.html#elasticsearch-ingest-data-through-integrations-connector-client-available-connectors`, + integrationsConnectorClientRunFromSource: `${SERVERLESS_DOCS}elasticsearch-ingest-data-through-integrations-connector-client.html#elasticsearch-ingest-data-through-integrations-connector-client-run-from-source`, + integrationsConnectorClientRunWithDocker: `${SERVERLESS_DOCS}elasticsearch-ingest-data-through-integrations-connector-client.html#elasticsearch-ingest-data-through-integrations-connector-client-run-with-docker`, + gettingStartedExplore: `${SERVERLESS_DOCS}elasticsearch-get-started.html`, + gettingStartedIngest: `${SERVERLESS_DOCS}elasticsearch-get-started.html`, + gettingStartedSearch: `${SERVERLESS_DOCS}elasticsearch-get-started.html`, }, serverlessSecurity: { - apiKeyPrivileges: `${SERVERLESS_DOCS}api-keys#restrict-privileges`, + apiKeyPrivileges: `${SERVERLESS_DOCS}api-keys.html#api-keys-restrict-privileges`, }, synthetics: { featureRoles: isServerless - ? `${SERVERLESS_OBSERVABILITY_DOCS}synthetics-feature-roles` + ? `${SERVERLESS_DOCS}observability-synthetics-feature-roles.html` : `${OBSERVABILITY_DOCS}synthetics-feature-roles.html`, }, telemetry: { diff --git a/packages/kbn-doc-links/src/types.ts b/packages/kbn-doc-links/src/types.ts index 0bfb1c69fd6b..f1a6a8d4b578 100644 --- a/packages/kbn-doc-links/src/types.ts +++ b/packages/kbn-doc-links/src/types.ts @@ -314,6 +314,7 @@ export interface DocLinks { readonly autocompleteSuggestions: string; readonly secureSavedObject: string; readonly xpackSecurity: string; + readonly dashboardImportExport: string; }; readonly upgradeAssistant: { readonly overview: string; diff --git a/packages/kbn-esql-ast/src/antlr/esql_lexer.g4 b/packages/kbn-esql-ast/src/antlr/esql_lexer.g4 index 0ffee7c0b0d4..ad17de2984ad 100644 --- a/packages/kbn-esql-ast/src/antlr/esql_lexer.g4 +++ b/packages/kbn-esql-ast/src/antlr/esql_lexer.g4 @@ -107,6 +107,8 @@ WS : [ \r\n\t]+ -> channel(HIDDEN) ; +COLON : ':'; + // // Expression - used by most command // @@ -209,8 +211,8 @@ MINUS : '-'; ASTERISK : '*'; SLASH : '/'; PERCENT : '%'; +EXPRESSION_COLON : {this.isDevVersion()}? COLON -> type(COLON); -MATCH : 'match'; NESTED_WHERE : WHERE -> type(WHERE); NAMED_OR_POSITIONAL_PARAM @@ -479,7 +481,7 @@ SHOW_WS mode SETTING_MODE; SETTING_CLOSING_BRACKET : CLOSING_BRACKET -> type(CLOSING_BRACKET), popMode; -COLON : ':'; +SETTING_COLON : COLON -> type(COLON); SETTING : (ASPERAND | DIGIT| DOT | LETTER | UNDERSCORE)+ diff --git a/packages/kbn-esql-ast/src/antlr/esql_lexer.interp b/packages/kbn-esql-ast/src/antlr/esql_lexer.interp index 2566da379af7..8f9c5956dddd 100644 --- a/packages/kbn-esql-ast/src/antlr/esql_lexer.interp +++ b/packages/kbn-esql-ast/src/antlr/esql_lexer.interp @@ -23,6 +23,7 @@ null null null null +':' '|' null null @@ -62,7 +63,6 @@ null '*' '/' '%' -'match' null null ']' @@ -103,7 +103,6 @@ null null null null -':' null null null @@ -146,6 +145,7 @@ UNKNOWN_CMD LINE_COMMENT MULTILINE_COMMENT WS +COLON PIPE QUOTED_STRING INTEGER_LITERAL @@ -185,7 +185,6 @@ MINUS ASTERISK SLASH PERCENT -MATCH NAMED_OR_POSITIONAL_PARAM OPENING_BRACKET CLOSING_BRACKET @@ -226,7 +225,6 @@ INFO SHOW_LINE_COMMENT SHOW_MULTILINE_COMMENT SHOW_WS -COLON SETTING SETTING_LINE_COMMENT SETTTING_MULTILINE_COMMENT @@ -268,6 +266,7 @@ UNKNOWN_CMD LINE_COMMENT MULTILINE_COMMENT WS +COLON PIPE DIGIT LETTER @@ -317,7 +316,7 @@ MINUS ASTERISK SLASH PERCENT -MATCH +EXPRESSION_COLON NESTED_WHERE NAMED_OR_POSITIONAL_PARAM OPENING_BRACKET @@ -406,7 +405,7 @@ SHOW_LINE_COMMENT SHOW_MULTILINE_COMMENT SHOW_WS SETTING_CLOSING_BRACKET -COLON +SETTING_COLON SETTING SETTING_LINE_COMMENT SETTTING_MULTILINE_COMMENT @@ -466,4 +465,4 @@ METRICS_MODE CLOSING_METRICS_MODE atn: -[4, 0, 120, 1479, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139, 2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144, 7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148, 2, 149, 7, 149, 2, 150, 7, 150, 2, 151, 7, 151, 2, 152, 7, 152, 2, 153, 7, 153, 2, 154, 7, 154, 2, 155, 7, 155, 2, 156, 7, 156, 2, 157, 7, 157, 2, 158, 7, 158, 2, 159, 7, 159, 2, 160, 7, 160, 2, 161, 7, 161, 2, 162, 7, 162, 2, 163, 7, 163, 2, 164, 7, 164, 2, 165, 7, 165, 2, 166, 7, 166, 2, 167, 7, 167, 2, 168, 7, 168, 2, 169, 7, 169, 2, 170, 7, 170, 2, 171, 7, 171, 2, 172, 7, 172, 2, 173, 7, 173, 2, 174, 7, 174, 2, 175, 7, 175, 2, 176, 7, 176, 2, 177, 7, 177, 2, 178, 7, 178, 2, 179, 7, 179, 2, 180, 7, 180, 2, 181, 7, 181, 2, 182, 7, 182, 2, 183, 7, 183, 2, 184, 7, 184, 2, 185, 7, 185, 2, 186, 7, 186, 2, 187, 7, 187, 2, 188, 7, 188, 2, 189, 7, 189, 2, 190, 7, 190, 2, 191, 7, 191, 2, 192, 7, 192, 2, 193, 7, 193, 2, 194, 7, 194, 2, 195, 7, 195, 2, 196, 7, 196, 2, 197, 7, 197, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 4, 19, 578, 8, 19, 11, 19, 12, 19, 579, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 5, 20, 588, 8, 20, 10, 20, 12, 20, 591, 9, 20, 1, 20, 3, 20, 594, 8, 20, 1, 20, 3, 20, 597, 8, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 5, 21, 606, 8, 21, 10, 21, 12, 21, 609, 9, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 4, 22, 617, 8, 22, 11, 22, 12, 22, 618, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 28, 1, 28, 3, 28, 638, 8, 28, 1, 28, 4, 28, 641, 8, 28, 11, 28, 12, 28, 642, 1, 29, 1, 29, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 3, 31, 652, 8, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 3, 33, 659, 8, 33, 1, 34, 1, 34, 1, 34, 5, 34, 664, 8, 34, 10, 34, 12, 34, 667, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 675, 8, 34, 10, 34, 12, 34, 678, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 3, 34, 685, 8, 34, 1, 34, 3, 34, 688, 8, 34, 3, 34, 690, 8, 34, 1, 35, 4, 35, 693, 8, 35, 11, 35, 12, 35, 694, 1, 36, 4, 36, 698, 8, 36, 11, 36, 12, 36, 699, 1, 36, 1, 36, 5, 36, 704, 8, 36, 10, 36, 12, 36, 707, 9, 36, 1, 36, 1, 36, 4, 36, 711, 8, 36, 11, 36, 12, 36, 712, 1, 36, 4, 36, 716, 8, 36, 11, 36, 12, 36, 717, 1, 36, 1, 36, 5, 36, 722, 8, 36, 10, 36, 12, 36, 725, 9, 36, 3, 36, 727, 8, 36, 1, 36, 1, 36, 1, 36, 1, 36, 4, 36, 733, 8, 36, 11, 36, 12, 36, 734, 1, 36, 1, 36, 3, 36, 739, 8, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 68, 1, 68, 1, 69, 1, 69, 1, 70, 1, 70, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 3, 74, 871, 8, 74, 1, 74, 5, 74, 874, 8, 74, 10, 74, 12, 74, 877, 9, 74, 1, 74, 1, 74, 4, 74, 881, 8, 74, 11, 74, 12, 74, 882, 3, 74, 885, 8, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 5, 77, 899, 8, 77, 10, 77, 12, 77, 902, 9, 77, 1, 77, 1, 77, 3, 77, 906, 8, 77, 1, 77, 4, 77, 909, 8, 77, 11, 77, 12, 77, 910, 3, 77, 913, 8, 77, 1, 78, 1, 78, 4, 78, 917, 8, 78, 11, 78, 12, 78, 918, 1, 78, 1, 78, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 3, 95, 996, 8, 95, 1, 96, 4, 96, 999, 8, 96, 11, 96, 12, 96, 1000, 1, 97, 1, 97, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 103, 1, 103, 1, 103, 1, 103, 1, 104, 1, 104, 1, 104, 1, 104, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 1, 107, 3, 107, 1050, 8, 107, 1, 108, 1, 108, 3, 108, 1054, 8, 108, 1, 108, 5, 108, 1057, 8, 108, 10, 108, 12, 108, 1060, 9, 108, 1, 108, 1, 108, 3, 108, 1064, 8, 108, 1, 108, 4, 108, 1067, 8, 108, 11, 108, 12, 108, 1068, 3, 108, 1071, 8, 108, 1, 109, 1, 109, 4, 109, 1075, 8, 109, 11, 109, 12, 109, 1076, 1, 110, 1, 110, 1, 110, 1, 110, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1, 115, 1, 115, 1, 116, 1, 116, 1, 116, 1, 116, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1, 119, 1, 120, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 121, 1, 121, 1, 122, 1, 122, 1, 122, 1, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 126, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1, 127, 1, 127, 1, 127, 1, 128, 1, 128, 1, 129, 4, 129, 1162, 8, 129, 11, 129, 12, 129, 1163, 1, 129, 1, 129, 3, 129, 1168, 8, 129, 1, 129, 4, 129, 1171, 8, 129, 11, 129, 12, 129, 1172, 1, 130, 1, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 131, 1, 131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 133, 1, 133, 1, 133, 1, 133, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 135, 1, 135, 1, 135, 1, 135, 1, 136, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 137, 1, 137, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 1, 142, 1, 143, 1, 143, 1, 143, 1, 143, 1, 144, 1, 144, 1, 144, 1, 144, 1, 145, 1, 145, 1, 145, 1, 145, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 148, 1, 148, 1, 148, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1, 151, 1, 151, 1, 152, 1, 152, 1, 152, 1, 152, 1, 153, 1, 153, 1, 153, 1, 153, 1, 154, 1, 154, 1, 154, 1, 154, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 1, 157, 1, 157, 1, 157, 1, 157, 1, 158, 1, 158, 1, 158, 1, 158, 1, 159, 1, 159, 1, 159, 1, 159, 1, 160, 1, 160, 1, 160, 1, 160, 1, 160, 1, 161, 1, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 4, 162, 1316, 8, 162, 11, 162, 12, 162, 1317, 1, 163, 1, 163, 1, 163, 1, 163, 1, 164, 1, 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1, 165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1, 168, 1, 168, 1, 168, 1, 169, 1, 169, 1, 169, 1, 169, 1, 170, 1, 170, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 173, 1, 173, 1, 173, 1, 173, 1, 174, 1, 174, 1, 174, 1, 174, 1, 175, 1, 175, 1, 175, 1, 175, 1, 176, 1, 176, 1, 176, 1, 176, 1, 176, 1, 176, 1, 177, 1, 177, 1, 177, 1, 177, 1, 178, 1, 178, 1, 178, 1, 178, 1, 179, 1, 179, 1, 179, 1, 179, 1, 180, 1, 180, 1, 180, 1, 180, 1, 181, 1, 181, 1, 181, 1, 181, 1, 182, 1, 182, 1, 182, 1, 182, 1, 183, 1, 183, 1, 183, 1, 183, 1, 183, 1, 184, 1, 184, 1, 184, 1, 184, 1, 184, 1, 184, 1, 185, 1, 185, 1, 185, 1, 185, 1, 185, 1, 185, 1, 186, 1, 186, 1, 186, 1, 186, 1, 187, 1, 187, 1, 187, 1, 187, 1, 188, 1, 188, 1, 188, 1, 188, 1, 189, 1, 189, 1, 189, 1, 189, 1, 189, 1, 189, 1, 190, 1, 190, 1, 190, 1, 190, 1, 190, 1, 190, 1, 191, 1, 191, 1, 191, 1, 191, 1, 192, 1, 192, 1, 192, 1, 192, 1, 193, 1, 193, 1, 193, 1, 193, 1, 194, 1, 194, 1, 194, 1, 194, 1, 194, 1, 194, 1, 195, 1, 195, 1, 195, 1, 195, 1, 195, 1, 195, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 197, 1, 197, 1, 197, 1, 197, 1, 197, 2, 607, 676, 0, 198, 15, 1, 17, 2, 19, 3, 21, 4, 23, 5, 25, 6, 27, 7, 29, 8, 31, 9, 33, 10, 35, 11, 37, 12, 39, 13, 41, 14, 43, 15, 45, 16, 47, 17, 49, 18, 51, 19, 53, 20, 55, 21, 57, 22, 59, 23, 61, 24, 63, 0, 65, 0, 67, 0, 69, 0, 71, 0, 73, 0, 75, 0, 77, 0, 79, 0, 81, 0, 83, 25, 85, 26, 87, 27, 89, 28, 91, 29, 93, 30, 95, 31, 97, 32, 99, 33, 101, 34, 103, 35, 105, 36, 107, 37, 109, 38, 111, 39, 113, 40, 115, 41, 117, 42, 119, 43, 121, 44, 123, 45, 125, 46, 127, 47, 129, 48, 131, 49, 133, 50, 135, 51, 137, 52, 139, 53, 141, 54, 143, 55, 145, 56, 147, 57, 149, 58, 151, 59, 153, 60, 155, 61, 157, 62, 159, 63, 161, 0, 163, 64, 165, 65, 167, 66, 169, 67, 171, 0, 173, 68, 175, 69, 177, 70, 179, 71, 181, 0, 183, 0, 185, 72, 187, 73, 189, 74, 191, 0, 193, 0, 195, 0, 197, 0, 199, 0, 201, 0, 203, 75, 205, 0, 207, 76, 209, 0, 211, 0, 213, 77, 215, 78, 217, 79, 219, 0, 221, 0, 223, 0, 225, 0, 227, 0, 229, 0, 231, 0, 233, 80, 235, 81, 237, 82, 239, 83, 241, 0, 243, 0, 245, 0, 247, 0, 249, 0, 251, 0, 253, 84, 255, 0, 257, 85, 259, 86, 261, 87, 263, 0, 265, 0, 267, 88, 269, 89, 271, 0, 273, 90, 275, 0, 277, 91, 279, 92, 281, 93, 283, 0, 285, 0, 287, 0, 289, 0, 291, 0, 293, 0, 295, 0, 297, 0, 299, 0, 301, 94, 303, 95, 305, 96, 307, 0, 309, 0, 311, 0, 313, 0, 315, 0, 317, 0, 319, 97, 321, 98, 323, 99, 325, 0, 327, 100, 329, 101, 331, 102, 333, 103, 335, 0, 337, 104, 339, 105, 341, 106, 343, 107, 345, 108, 347, 0, 349, 0, 351, 0, 353, 0, 355, 0, 357, 0, 359, 0, 361, 109, 363, 110, 365, 111, 367, 0, 369, 0, 371, 0, 373, 0, 375, 112, 377, 113, 379, 114, 381, 0, 383, 0, 385, 0, 387, 115, 389, 116, 391, 117, 393, 0, 395, 0, 397, 118, 399, 119, 401, 120, 403, 0, 405, 0, 407, 0, 409, 0, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 35, 2, 0, 68, 68, 100, 100, 2, 0, 73, 73, 105, 105, 2, 0, 83, 83, 115, 115, 2, 0, 69, 69, 101, 101, 2, 0, 67, 67, 99, 99, 2, 0, 84, 84, 116, 116, 2, 0, 82, 82, 114, 114, 2, 0, 79, 79, 111, 111, 2, 0, 80, 80, 112, 112, 2, 0, 78, 78, 110, 110, 2, 0, 72, 72, 104, 104, 2, 0, 86, 86, 118, 118, 2, 0, 65, 65, 97, 97, 2, 0, 76, 76, 108, 108, 2, 0, 88, 88, 120, 120, 2, 0, 70, 70, 102, 102, 2, 0, 77, 77, 109, 109, 2, 0, 71, 71, 103, 103, 2, 0, 75, 75, 107, 107, 2, 0, 87, 87, 119, 119, 2, 0, 85, 85, 117, 117, 6, 0, 9, 10, 13, 13, 32, 32, 47, 47, 91, 91, 93, 93, 2, 0, 10, 10, 13, 13, 3, 0, 9, 10, 13, 13, 32, 32, 1, 0, 48, 57, 2, 0, 65, 90, 97, 122, 8, 0, 34, 34, 78, 78, 82, 82, 84, 84, 92, 92, 110, 110, 114, 114, 116, 116, 4, 0, 10, 10, 13, 13, 34, 34, 92, 92, 2, 0, 43, 43, 45, 45, 1, 0, 96, 96, 2, 0, 66, 66, 98, 98, 2, 0, 89, 89, 121, 121, 11, 0, 9, 10, 13, 13, 32, 32, 34, 34, 44, 44, 47, 47, 58, 58, 61, 61, 91, 91, 93, 93, 124, 124, 2, 0, 42, 42, 47, 47, 11, 0, 9, 10, 13, 13, 32, 32, 34, 35, 44, 44, 47, 47, 58, 58, 60, 60, 62, 63, 92, 92, 124, 124, 1507, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 1, 61, 1, 0, 0, 0, 1, 83, 1, 0, 0, 0, 1, 85, 1, 0, 0, 0, 1, 87, 1, 0, 0, 0, 1, 89, 1, 0, 0, 0, 1, 91, 1, 0, 0, 0, 1, 93, 1, 0, 0, 0, 1, 95, 1, 0, 0, 0, 1, 97, 1, 0, 0, 0, 1, 99, 1, 0, 0, 0, 1, 101, 1, 0, 0, 0, 1, 103, 1, 0, 0, 0, 1, 105, 1, 0, 0, 0, 1, 107, 1, 0, 0, 0, 1, 109, 1, 0, 0, 0, 1, 111, 1, 0, 0, 0, 1, 113, 1, 0, 0, 0, 1, 115, 1, 0, 0, 0, 1, 117, 1, 0, 0, 0, 1, 119, 1, 0, 0, 0, 1, 121, 1, 0, 0, 0, 1, 123, 1, 0, 0, 0, 1, 125, 1, 0, 0, 0, 1, 127, 1, 0, 0, 0, 1, 129, 1, 0, 0, 0, 1, 131, 1, 0, 0, 0, 1, 133, 1, 0, 0, 0, 1, 135, 1, 0, 0, 0, 1, 137, 1, 0, 0, 0, 1, 139, 1, 0, 0, 0, 1, 141, 1, 0, 0, 0, 1, 143, 1, 0, 0, 0, 1, 145, 1, 0, 0, 0, 1, 147, 1, 0, 0, 0, 1, 149, 1, 0, 0, 0, 1, 151, 1, 0, 0, 0, 1, 153, 1, 0, 0, 0, 1, 155, 1, 0, 0, 0, 1, 157, 1, 0, 0, 0, 1, 159, 1, 0, 0, 0, 1, 161, 1, 0, 0, 0, 1, 163, 1, 0, 0, 0, 1, 165, 1, 0, 0, 0, 1, 167, 1, 0, 0, 0, 1, 169, 1, 0, 0, 0, 1, 173, 1, 0, 0, 0, 1, 175, 1, 0, 0, 0, 1, 177, 1, 0, 0, 0, 1, 179, 1, 0, 0, 0, 2, 181, 1, 0, 0, 0, 2, 183, 1, 0, 0, 0, 2, 185, 1, 0, 0, 0, 2, 187, 1, 0, 0, 0, 2, 189, 1, 0, 0, 0, 3, 191, 1, 0, 0, 0, 3, 193, 1, 0, 0, 0, 3, 195, 1, 0, 0, 0, 3, 197, 1, 0, 0, 0, 3, 199, 1, 0, 0, 0, 3, 201, 1, 0, 0, 0, 3, 203, 1, 0, 0, 0, 3, 207, 1, 0, 0, 0, 3, 209, 1, 0, 0, 0, 3, 211, 1, 0, 0, 0, 3, 213, 1, 0, 0, 0, 3, 215, 1, 0, 0, 0, 3, 217, 1, 0, 0, 0, 4, 219, 1, 0, 0, 0, 4, 221, 1, 0, 0, 0, 4, 223, 1, 0, 0, 0, 4, 225, 1, 0, 0, 0, 4, 227, 1, 0, 0, 0, 4, 233, 1, 0, 0, 0, 4, 235, 1, 0, 0, 0, 4, 237, 1, 0, 0, 0, 4, 239, 1, 0, 0, 0, 5, 241, 1, 0, 0, 0, 5, 243, 1, 0, 0, 0, 5, 245, 1, 0, 0, 0, 5, 247, 1, 0, 0, 0, 5, 249, 1, 0, 0, 0, 5, 251, 1, 0, 0, 0, 5, 253, 1, 0, 0, 0, 5, 255, 1, 0, 0, 0, 5, 257, 1, 0, 0, 0, 5, 259, 1, 0, 0, 0, 5, 261, 1, 0, 0, 0, 6, 263, 1, 0, 0, 0, 6, 265, 1, 0, 0, 0, 6, 267, 1, 0, 0, 0, 6, 269, 1, 0, 0, 0, 6, 273, 1, 0, 0, 0, 6, 275, 1, 0, 0, 0, 6, 277, 1, 0, 0, 0, 6, 279, 1, 0, 0, 0, 6, 281, 1, 0, 0, 0, 7, 283, 1, 0, 0, 0, 7, 285, 1, 0, 0, 0, 7, 287, 1, 0, 0, 0, 7, 289, 1, 0, 0, 0, 7, 291, 1, 0, 0, 0, 7, 293, 1, 0, 0, 0, 7, 295, 1, 0, 0, 0, 7, 297, 1, 0, 0, 0, 7, 299, 1, 0, 0, 0, 7, 301, 1, 0, 0, 0, 7, 303, 1, 0, 0, 0, 7, 305, 1, 0, 0, 0, 8, 307, 1, 0, 0, 0, 8, 309, 1, 0, 0, 0, 8, 311, 1, 0, 0, 0, 8, 313, 1, 0, 0, 0, 8, 315, 1, 0, 0, 0, 8, 317, 1, 0, 0, 0, 8, 319, 1, 0, 0, 0, 8, 321, 1, 0, 0, 0, 8, 323, 1, 0, 0, 0, 9, 325, 1, 0, 0, 0, 9, 327, 1, 0, 0, 0, 9, 329, 1, 0, 0, 0, 9, 331, 1, 0, 0, 0, 9, 333, 1, 0, 0, 0, 10, 335, 1, 0, 0, 0, 10, 337, 1, 0, 0, 0, 10, 339, 1, 0, 0, 0, 10, 341, 1, 0, 0, 0, 10, 343, 1, 0, 0, 0, 10, 345, 1, 0, 0, 0, 11, 347, 1, 0, 0, 0, 11, 349, 1, 0, 0, 0, 11, 351, 1, 0, 0, 0, 11, 353, 1, 0, 0, 0, 11, 355, 1, 0, 0, 0, 11, 357, 1, 0, 0, 0, 11, 359, 1, 0, 0, 0, 11, 361, 1, 0, 0, 0, 11, 363, 1, 0, 0, 0, 11, 365, 1, 0, 0, 0, 12, 367, 1, 0, 0, 0, 12, 369, 1, 0, 0, 0, 12, 371, 1, 0, 0, 0, 12, 373, 1, 0, 0, 0, 12, 375, 1, 0, 0, 0, 12, 377, 1, 0, 0, 0, 12, 379, 1, 0, 0, 0, 13, 381, 1, 0, 0, 0, 13, 383, 1, 0, 0, 0, 13, 385, 1, 0, 0, 0, 13, 387, 1, 0, 0, 0, 13, 389, 1, 0, 0, 0, 13, 391, 1, 0, 0, 0, 14, 393, 1, 0, 0, 0, 14, 395, 1, 0, 0, 0, 14, 397, 1, 0, 0, 0, 14, 399, 1, 0, 0, 0, 14, 401, 1, 0, 0, 0, 14, 403, 1, 0, 0, 0, 14, 405, 1, 0, 0, 0, 14, 407, 1, 0, 0, 0, 14, 409, 1, 0, 0, 0, 15, 411, 1, 0, 0, 0, 17, 421, 1, 0, 0, 0, 19, 428, 1, 0, 0, 0, 21, 437, 1, 0, 0, 0, 23, 444, 1, 0, 0, 0, 25, 454, 1, 0, 0, 0, 27, 461, 1, 0, 0, 0, 29, 468, 1, 0, 0, 0, 31, 475, 1, 0, 0, 0, 33, 483, 1, 0, 0, 0, 35, 495, 1, 0, 0, 0, 37, 504, 1, 0, 0, 0, 39, 510, 1, 0, 0, 0, 41, 517, 1, 0, 0, 0, 43, 524, 1, 0, 0, 0, 45, 532, 1, 0, 0, 0, 47, 540, 1, 0, 0, 0, 49, 555, 1, 0, 0, 0, 51, 565, 1, 0, 0, 0, 53, 577, 1, 0, 0, 0, 55, 583, 1, 0, 0, 0, 57, 600, 1, 0, 0, 0, 59, 616, 1, 0, 0, 0, 61, 622, 1, 0, 0, 0, 63, 626, 1, 0, 0, 0, 65, 628, 1, 0, 0, 0, 67, 630, 1, 0, 0, 0, 69, 633, 1, 0, 0, 0, 71, 635, 1, 0, 0, 0, 73, 644, 1, 0, 0, 0, 75, 646, 1, 0, 0, 0, 77, 651, 1, 0, 0, 0, 79, 653, 1, 0, 0, 0, 81, 658, 1, 0, 0, 0, 83, 689, 1, 0, 0, 0, 85, 692, 1, 0, 0, 0, 87, 738, 1, 0, 0, 0, 89, 740, 1, 0, 0, 0, 91, 743, 1, 0, 0, 0, 93, 747, 1, 0, 0, 0, 95, 751, 1, 0, 0, 0, 97, 753, 1, 0, 0, 0, 99, 756, 1, 0, 0, 0, 101, 758, 1, 0, 0, 0, 103, 763, 1, 0, 0, 0, 105, 765, 1, 0, 0, 0, 107, 771, 1, 0, 0, 0, 109, 777, 1, 0, 0, 0, 111, 780, 1, 0, 0, 0, 113, 783, 1, 0, 0, 0, 115, 788, 1, 0, 0, 0, 117, 793, 1, 0, 0, 0, 119, 795, 1, 0, 0, 0, 121, 799, 1, 0, 0, 0, 123, 804, 1, 0, 0, 0, 125, 810, 1, 0, 0, 0, 127, 813, 1, 0, 0, 0, 129, 815, 1, 0, 0, 0, 131, 821, 1, 0, 0, 0, 133, 823, 1, 0, 0, 0, 135, 828, 1, 0, 0, 0, 137, 831, 1, 0, 0, 0, 139, 834, 1, 0, 0, 0, 141, 837, 1, 0, 0, 0, 143, 839, 1, 0, 0, 0, 145, 842, 1, 0, 0, 0, 147, 844, 1, 0, 0, 0, 149, 847, 1, 0, 0, 0, 151, 849, 1, 0, 0, 0, 153, 851, 1, 0, 0, 0, 155, 853, 1, 0, 0, 0, 157, 855, 1, 0, 0, 0, 159, 857, 1, 0, 0, 0, 161, 863, 1, 0, 0, 0, 163, 884, 1, 0, 0, 0, 165, 886, 1, 0, 0, 0, 167, 891, 1, 0, 0, 0, 169, 912, 1, 0, 0, 0, 171, 914, 1, 0, 0, 0, 173, 922, 1, 0, 0, 0, 175, 924, 1, 0, 0, 0, 177, 928, 1, 0, 0, 0, 179, 932, 1, 0, 0, 0, 181, 936, 1, 0, 0, 0, 183, 941, 1, 0, 0, 0, 185, 946, 1, 0, 0, 0, 187, 950, 1, 0, 0, 0, 189, 954, 1, 0, 0, 0, 191, 958, 1, 0, 0, 0, 193, 963, 1, 0, 0, 0, 195, 967, 1, 0, 0, 0, 197, 971, 1, 0, 0, 0, 199, 975, 1, 0, 0, 0, 201, 979, 1, 0, 0, 0, 203, 983, 1, 0, 0, 0, 205, 995, 1, 0, 0, 0, 207, 998, 1, 0, 0, 0, 209, 1002, 1, 0, 0, 0, 211, 1006, 1, 0, 0, 0, 213, 1010, 1, 0, 0, 0, 215, 1014, 1, 0, 0, 0, 217, 1018, 1, 0, 0, 0, 219, 1022, 1, 0, 0, 0, 221, 1027, 1, 0, 0, 0, 223, 1031, 1, 0, 0, 0, 225, 1035, 1, 0, 0, 0, 227, 1040, 1, 0, 0, 0, 229, 1049, 1, 0, 0, 0, 231, 1070, 1, 0, 0, 0, 233, 1074, 1, 0, 0, 0, 235, 1078, 1, 0, 0, 0, 237, 1082, 1, 0, 0, 0, 239, 1086, 1, 0, 0, 0, 241, 1090, 1, 0, 0, 0, 243, 1095, 1, 0, 0, 0, 245, 1099, 1, 0, 0, 0, 247, 1103, 1, 0, 0, 0, 249, 1107, 1, 0, 0, 0, 251, 1112, 1, 0, 0, 0, 253, 1117, 1, 0, 0, 0, 255, 1120, 1, 0, 0, 0, 257, 1124, 1, 0, 0, 0, 259, 1128, 1, 0, 0, 0, 261, 1132, 1, 0, 0, 0, 263, 1136, 1, 0, 0, 0, 265, 1141, 1, 0, 0, 0, 267, 1146, 1, 0, 0, 0, 269, 1151, 1, 0, 0, 0, 271, 1158, 1, 0, 0, 0, 273, 1167, 1, 0, 0, 0, 275, 1174, 1, 0, 0, 0, 277, 1178, 1, 0, 0, 0, 279, 1182, 1, 0, 0, 0, 281, 1186, 1, 0, 0, 0, 283, 1190, 1, 0, 0, 0, 285, 1196, 1, 0, 0, 0, 287, 1200, 1, 0, 0, 0, 289, 1204, 1, 0, 0, 0, 291, 1208, 1, 0, 0, 0, 293, 1212, 1, 0, 0, 0, 295, 1216, 1, 0, 0, 0, 297, 1220, 1, 0, 0, 0, 299, 1225, 1, 0, 0, 0, 301, 1230, 1, 0, 0, 0, 303, 1234, 1, 0, 0, 0, 305, 1238, 1, 0, 0, 0, 307, 1242, 1, 0, 0, 0, 309, 1247, 1, 0, 0, 0, 311, 1251, 1, 0, 0, 0, 313, 1256, 1, 0, 0, 0, 315, 1261, 1, 0, 0, 0, 317, 1265, 1, 0, 0, 0, 319, 1269, 1, 0, 0, 0, 321, 1273, 1, 0, 0, 0, 323, 1277, 1, 0, 0, 0, 325, 1281, 1, 0, 0, 0, 327, 1286, 1, 0, 0, 0, 329, 1291, 1, 0, 0, 0, 331, 1295, 1, 0, 0, 0, 333, 1299, 1, 0, 0, 0, 335, 1303, 1, 0, 0, 0, 337, 1308, 1, 0, 0, 0, 339, 1315, 1, 0, 0, 0, 341, 1319, 1, 0, 0, 0, 343, 1323, 1, 0, 0, 0, 345, 1327, 1, 0, 0, 0, 347, 1331, 1, 0, 0, 0, 349, 1336, 1, 0, 0, 0, 351, 1340, 1, 0, 0, 0, 353, 1344, 1, 0, 0, 0, 355, 1348, 1, 0, 0, 0, 357, 1353, 1, 0, 0, 0, 359, 1357, 1, 0, 0, 0, 361, 1361, 1, 0, 0, 0, 363, 1365, 1, 0, 0, 0, 365, 1369, 1, 0, 0, 0, 367, 1373, 1, 0, 0, 0, 369, 1379, 1, 0, 0, 0, 371, 1383, 1, 0, 0, 0, 373, 1387, 1, 0, 0, 0, 375, 1391, 1, 0, 0, 0, 377, 1395, 1, 0, 0, 0, 379, 1399, 1, 0, 0, 0, 381, 1403, 1, 0, 0, 0, 383, 1408, 1, 0, 0, 0, 385, 1414, 1, 0, 0, 0, 387, 1420, 1, 0, 0, 0, 389, 1424, 1, 0, 0, 0, 391, 1428, 1, 0, 0, 0, 393, 1432, 1, 0, 0, 0, 395, 1438, 1, 0, 0, 0, 397, 1444, 1, 0, 0, 0, 399, 1448, 1, 0, 0, 0, 401, 1452, 1, 0, 0, 0, 403, 1456, 1, 0, 0, 0, 405, 1462, 1, 0, 0, 0, 407, 1468, 1, 0, 0, 0, 409, 1474, 1, 0, 0, 0, 411, 412, 7, 0, 0, 0, 412, 413, 7, 1, 0, 0, 413, 414, 7, 2, 0, 0, 414, 415, 7, 2, 0, 0, 415, 416, 7, 3, 0, 0, 416, 417, 7, 4, 0, 0, 417, 418, 7, 5, 0, 0, 418, 419, 1, 0, 0, 0, 419, 420, 6, 0, 0, 0, 420, 16, 1, 0, 0, 0, 421, 422, 7, 0, 0, 0, 422, 423, 7, 6, 0, 0, 423, 424, 7, 7, 0, 0, 424, 425, 7, 8, 0, 0, 425, 426, 1, 0, 0, 0, 426, 427, 6, 1, 1, 0, 427, 18, 1, 0, 0, 0, 428, 429, 7, 3, 0, 0, 429, 430, 7, 9, 0, 0, 430, 431, 7, 6, 0, 0, 431, 432, 7, 1, 0, 0, 432, 433, 7, 4, 0, 0, 433, 434, 7, 10, 0, 0, 434, 435, 1, 0, 0, 0, 435, 436, 6, 2, 2, 0, 436, 20, 1, 0, 0, 0, 437, 438, 7, 3, 0, 0, 438, 439, 7, 11, 0, 0, 439, 440, 7, 12, 0, 0, 440, 441, 7, 13, 0, 0, 441, 442, 1, 0, 0, 0, 442, 443, 6, 3, 0, 0, 443, 22, 1, 0, 0, 0, 444, 445, 7, 3, 0, 0, 445, 446, 7, 14, 0, 0, 446, 447, 7, 8, 0, 0, 447, 448, 7, 13, 0, 0, 448, 449, 7, 12, 0, 0, 449, 450, 7, 1, 0, 0, 450, 451, 7, 9, 0, 0, 451, 452, 1, 0, 0, 0, 452, 453, 6, 4, 3, 0, 453, 24, 1, 0, 0, 0, 454, 455, 7, 15, 0, 0, 455, 456, 7, 6, 0, 0, 456, 457, 7, 7, 0, 0, 457, 458, 7, 16, 0, 0, 458, 459, 1, 0, 0, 0, 459, 460, 6, 5, 4, 0, 460, 26, 1, 0, 0, 0, 461, 462, 7, 17, 0, 0, 462, 463, 7, 6, 0, 0, 463, 464, 7, 7, 0, 0, 464, 465, 7, 18, 0, 0, 465, 466, 1, 0, 0, 0, 466, 467, 6, 6, 0, 0, 467, 28, 1, 0, 0, 0, 468, 469, 7, 18, 0, 0, 469, 470, 7, 3, 0, 0, 470, 471, 7, 3, 0, 0, 471, 472, 7, 8, 0, 0, 472, 473, 1, 0, 0, 0, 473, 474, 6, 7, 1, 0, 474, 30, 1, 0, 0, 0, 475, 476, 7, 13, 0, 0, 476, 477, 7, 1, 0, 0, 477, 478, 7, 16, 0, 0, 478, 479, 7, 1, 0, 0, 479, 480, 7, 5, 0, 0, 480, 481, 1, 0, 0, 0, 481, 482, 6, 8, 0, 0, 482, 32, 1, 0, 0, 0, 483, 484, 7, 16, 0, 0, 484, 485, 7, 11, 0, 0, 485, 486, 5, 95, 0, 0, 486, 487, 7, 3, 0, 0, 487, 488, 7, 14, 0, 0, 488, 489, 7, 8, 0, 0, 489, 490, 7, 12, 0, 0, 490, 491, 7, 9, 0, 0, 491, 492, 7, 0, 0, 0, 492, 493, 1, 0, 0, 0, 493, 494, 6, 9, 5, 0, 494, 34, 1, 0, 0, 0, 495, 496, 7, 6, 0, 0, 496, 497, 7, 3, 0, 0, 497, 498, 7, 9, 0, 0, 498, 499, 7, 12, 0, 0, 499, 500, 7, 16, 0, 0, 500, 501, 7, 3, 0, 0, 501, 502, 1, 0, 0, 0, 502, 503, 6, 10, 6, 0, 503, 36, 1, 0, 0, 0, 504, 505, 7, 6, 0, 0, 505, 506, 7, 7, 0, 0, 506, 507, 7, 19, 0, 0, 507, 508, 1, 0, 0, 0, 508, 509, 6, 11, 0, 0, 509, 38, 1, 0, 0, 0, 510, 511, 7, 2, 0, 0, 511, 512, 7, 10, 0, 0, 512, 513, 7, 7, 0, 0, 513, 514, 7, 19, 0, 0, 514, 515, 1, 0, 0, 0, 515, 516, 6, 12, 7, 0, 516, 40, 1, 0, 0, 0, 517, 518, 7, 2, 0, 0, 518, 519, 7, 7, 0, 0, 519, 520, 7, 6, 0, 0, 520, 521, 7, 5, 0, 0, 521, 522, 1, 0, 0, 0, 522, 523, 6, 13, 0, 0, 523, 42, 1, 0, 0, 0, 524, 525, 7, 2, 0, 0, 525, 526, 7, 5, 0, 0, 526, 527, 7, 12, 0, 0, 527, 528, 7, 5, 0, 0, 528, 529, 7, 2, 0, 0, 529, 530, 1, 0, 0, 0, 530, 531, 6, 14, 0, 0, 531, 44, 1, 0, 0, 0, 532, 533, 7, 19, 0, 0, 533, 534, 7, 10, 0, 0, 534, 535, 7, 3, 0, 0, 535, 536, 7, 6, 0, 0, 536, 537, 7, 3, 0, 0, 537, 538, 1, 0, 0, 0, 538, 539, 6, 15, 0, 0, 539, 46, 1, 0, 0, 0, 540, 541, 4, 16, 0, 0, 541, 542, 7, 1, 0, 0, 542, 543, 7, 9, 0, 0, 543, 544, 7, 13, 0, 0, 544, 545, 7, 1, 0, 0, 545, 546, 7, 9, 0, 0, 546, 547, 7, 3, 0, 0, 547, 548, 7, 2, 0, 0, 548, 549, 7, 5, 0, 0, 549, 550, 7, 12, 0, 0, 550, 551, 7, 5, 0, 0, 551, 552, 7, 2, 0, 0, 552, 553, 1, 0, 0, 0, 553, 554, 6, 16, 0, 0, 554, 48, 1, 0, 0, 0, 555, 556, 4, 17, 1, 0, 556, 557, 7, 13, 0, 0, 557, 558, 7, 7, 0, 0, 558, 559, 7, 7, 0, 0, 559, 560, 7, 18, 0, 0, 560, 561, 7, 20, 0, 0, 561, 562, 7, 8, 0, 0, 562, 563, 1, 0, 0, 0, 563, 564, 6, 17, 8, 0, 564, 50, 1, 0, 0, 0, 565, 566, 4, 18, 2, 0, 566, 567, 7, 16, 0, 0, 567, 568, 7, 3, 0, 0, 568, 569, 7, 5, 0, 0, 569, 570, 7, 6, 0, 0, 570, 571, 7, 1, 0, 0, 571, 572, 7, 4, 0, 0, 572, 573, 7, 2, 0, 0, 573, 574, 1, 0, 0, 0, 574, 575, 6, 18, 9, 0, 575, 52, 1, 0, 0, 0, 576, 578, 8, 21, 0, 0, 577, 576, 1, 0, 0, 0, 578, 579, 1, 0, 0, 0, 579, 577, 1, 0, 0, 0, 579, 580, 1, 0, 0, 0, 580, 581, 1, 0, 0, 0, 581, 582, 6, 19, 0, 0, 582, 54, 1, 0, 0, 0, 583, 584, 5, 47, 0, 0, 584, 585, 5, 47, 0, 0, 585, 589, 1, 0, 0, 0, 586, 588, 8, 22, 0, 0, 587, 586, 1, 0, 0, 0, 588, 591, 1, 0, 0, 0, 589, 587, 1, 0, 0, 0, 589, 590, 1, 0, 0, 0, 590, 593, 1, 0, 0, 0, 591, 589, 1, 0, 0, 0, 592, 594, 5, 13, 0, 0, 593, 592, 1, 0, 0, 0, 593, 594, 1, 0, 0, 0, 594, 596, 1, 0, 0, 0, 595, 597, 5, 10, 0, 0, 596, 595, 1, 0, 0, 0, 596, 597, 1, 0, 0, 0, 597, 598, 1, 0, 0, 0, 598, 599, 6, 20, 10, 0, 599, 56, 1, 0, 0, 0, 600, 601, 5, 47, 0, 0, 601, 602, 5, 42, 0, 0, 602, 607, 1, 0, 0, 0, 603, 606, 3, 57, 21, 0, 604, 606, 9, 0, 0, 0, 605, 603, 1, 0, 0, 0, 605, 604, 1, 0, 0, 0, 606, 609, 1, 0, 0, 0, 607, 608, 1, 0, 0, 0, 607, 605, 1, 0, 0, 0, 608, 610, 1, 0, 0, 0, 609, 607, 1, 0, 0, 0, 610, 611, 5, 42, 0, 0, 611, 612, 5, 47, 0, 0, 612, 613, 1, 0, 0, 0, 613, 614, 6, 21, 10, 0, 614, 58, 1, 0, 0, 0, 615, 617, 7, 23, 0, 0, 616, 615, 1, 0, 0, 0, 617, 618, 1, 0, 0, 0, 618, 616, 1, 0, 0, 0, 618, 619, 1, 0, 0, 0, 619, 620, 1, 0, 0, 0, 620, 621, 6, 22, 10, 0, 621, 60, 1, 0, 0, 0, 622, 623, 5, 124, 0, 0, 623, 624, 1, 0, 0, 0, 624, 625, 6, 23, 11, 0, 625, 62, 1, 0, 0, 0, 626, 627, 7, 24, 0, 0, 627, 64, 1, 0, 0, 0, 628, 629, 7, 25, 0, 0, 629, 66, 1, 0, 0, 0, 630, 631, 5, 92, 0, 0, 631, 632, 7, 26, 0, 0, 632, 68, 1, 0, 0, 0, 633, 634, 8, 27, 0, 0, 634, 70, 1, 0, 0, 0, 635, 637, 7, 3, 0, 0, 636, 638, 7, 28, 0, 0, 637, 636, 1, 0, 0, 0, 637, 638, 1, 0, 0, 0, 638, 640, 1, 0, 0, 0, 639, 641, 3, 63, 24, 0, 640, 639, 1, 0, 0, 0, 641, 642, 1, 0, 0, 0, 642, 640, 1, 0, 0, 0, 642, 643, 1, 0, 0, 0, 643, 72, 1, 0, 0, 0, 644, 645, 5, 64, 0, 0, 645, 74, 1, 0, 0, 0, 646, 647, 5, 96, 0, 0, 647, 76, 1, 0, 0, 0, 648, 652, 8, 29, 0, 0, 649, 650, 5, 96, 0, 0, 650, 652, 5, 96, 0, 0, 651, 648, 1, 0, 0, 0, 651, 649, 1, 0, 0, 0, 652, 78, 1, 0, 0, 0, 653, 654, 5, 95, 0, 0, 654, 80, 1, 0, 0, 0, 655, 659, 3, 65, 25, 0, 656, 659, 3, 63, 24, 0, 657, 659, 3, 79, 32, 0, 658, 655, 1, 0, 0, 0, 658, 656, 1, 0, 0, 0, 658, 657, 1, 0, 0, 0, 659, 82, 1, 0, 0, 0, 660, 665, 5, 34, 0, 0, 661, 664, 3, 67, 26, 0, 662, 664, 3, 69, 27, 0, 663, 661, 1, 0, 0, 0, 663, 662, 1, 0, 0, 0, 664, 667, 1, 0, 0, 0, 665, 663, 1, 0, 0, 0, 665, 666, 1, 0, 0, 0, 666, 668, 1, 0, 0, 0, 667, 665, 1, 0, 0, 0, 668, 690, 5, 34, 0, 0, 669, 670, 5, 34, 0, 0, 670, 671, 5, 34, 0, 0, 671, 672, 5, 34, 0, 0, 672, 676, 1, 0, 0, 0, 673, 675, 8, 22, 0, 0, 674, 673, 1, 0, 0, 0, 675, 678, 1, 0, 0, 0, 676, 677, 1, 0, 0, 0, 676, 674, 1, 0, 0, 0, 677, 679, 1, 0, 0, 0, 678, 676, 1, 0, 0, 0, 679, 680, 5, 34, 0, 0, 680, 681, 5, 34, 0, 0, 681, 682, 5, 34, 0, 0, 682, 684, 1, 0, 0, 0, 683, 685, 5, 34, 0, 0, 684, 683, 1, 0, 0, 0, 684, 685, 1, 0, 0, 0, 685, 687, 1, 0, 0, 0, 686, 688, 5, 34, 0, 0, 687, 686, 1, 0, 0, 0, 687, 688, 1, 0, 0, 0, 688, 690, 1, 0, 0, 0, 689, 660, 1, 0, 0, 0, 689, 669, 1, 0, 0, 0, 690, 84, 1, 0, 0, 0, 691, 693, 3, 63, 24, 0, 692, 691, 1, 0, 0, 0, 693, 694, 1, 0, 0, 0, 694, 692, 1, 0, 0, 0, 694, 695, 1, 0, 0, 0, 695, 86, 1, 0, 0, 0, 696, 698, 3, 63, 24, 0, 697, 696, 1, 0, 0, 0, 698, 699, 1, 0, 0, 0, 699, 697, 1, 0, 0, 0, 699, 700, 1, 0, 0, 0, 700, 701, 1, 0, 0, 0, 701, 705, 3, 103, 44, 0, 702, 704, 3, 63, 24, 0, 703, 702, 1, 0, 0, 0, 704, 707, 1, 0, 0, 0, 705, 703, 1, 0, 0, 0, 705, 706, 1, 0, 0, 0, 706, 739, 1, 0, 0, 0, 707, 705, 1, 0, 0, 0, 708, 710, 3, 103, 44, 0, 709, 711, 3, 63, 24, 0, 710, 709, 1, 0, 0, 0, 711, 712, 1, 0, 0, 0, 712, 710, 1, 0, 0, 0, 712, 713, 1, 0, 0, 0, 713, 739, 1, 0, 0, 0, 714, 716, 3, 63, 24, 0, 715, 714, 1, 0, 0, 0, 716, 717, 1, 0, 0, 0, 717, 715, 1, 0, 0, 0, 717, 718, 1, 0, 0, 0, 718, 726, 1, 0, 0, 0, 719, 723, 3, 103, 44, 0, 720, 722, 3, 63, 24, 0, 721, 720, 1, 0, 0, 0, 722, 725, 1, 0, 0, 0, 723, 721, 1, 0, 0, 0, 723, 724, 1, 0, 0, 0, 724, 727, 1, 0, 0, 0, 725, 723, 1, 0, 0, 0, 726, 719, 1, 0, 0, 0, 726, 727, 1, 0, 0, 0, 727, 728, 1, 0, 0, 0, 728, 729, 3, 71, 28, 0, 729, 739, 1, 0, 0, 0, 730, 732, 3, 103, 44, 0, 731, 733, 3, 63, 24, 0, 732, 731, 1, 0, 0, 0, 733, 734, 1, 0, 0, 0, 734, 732, 1, 0, 0, 0, 734, 735, 1, 0, 0, 0, 735, 736, 1, 0, 0, 0, 736, 737, 3, 71, 28, 0, 737, 739, 1, 0, 0, 0, 738, 697, 1, 0, 0, 0, 738, 708, 1, 0, 0, 0, 738, 715, 1, 0, 0, 0, 738, 730, 1, 0, 0, 0, 739, 88, 1, 0, 0, 0, 740, 741, 7, 30, 0, 0, 741, 742, 7, 31, 0, 0, 742, 90, 1, 0, 0, 0, 743, 744, 7, 12, 0, 0, 744, 745, 7, 9, 0, 0, 745, 746, 7, 0, 0, 0, 746, 92, 1, 0, 0, 0, 747, 748, 7, 12, 0, 0, 748, 749, 7, 2, 0, 0, 749, 750, 7, 4, 0, 0, 750, 94, 1, 0, 0, 0, 751, 752, 5, 61, 0, 0, 752, 96, 1, 0, 0, 0, 753, 754, 5, 58, 0, 0, 754, 755, 5, 58, 0, 0, 755, 98, 1, 0, 0, 0, 756, 757, 5, 44, 0, 0, 757, 100, 1, 0, 0, 0, 758, 759, 7, 0, 0, 0, 759, 760, 7, 3, 0, 0, 760, 761, 7, 2, 0, 0, 761, 762, 7, 4, 0, 0, 762, 102, 1, 0, 0, 0, 763, 764, 5, 46, 0, 0, 764, 104, 1, 0, 0, 0, 765, 766, 7, 15, 0, 0, 766, 767, 7, 12, 0, 0, 767, 768, 7, 13, 0, 0, 768, 769, 7, 2, 0, 0, 769, 770, 7, 3, 0, 0, 770, 106, 1, 0, 0, 0, 771, 772, 7, 15, 0, 0, 772, 773, 7, 1, 0, 0, 773, 774, 7, 6, 0, 0, 774, 775, 7, 2, 0, 0, 775, 776, 7, 5, 0, 0, 776, 108, 1, 0, 0, 0, 777, 778, 7, 1, 0, 0, 778, 779, 7, 9, 0, 0, 779, 110, 1, 0, 0, 0, 780, 781, 7, 1, 0, 0, 781, 782, 7, 2, 0, 0, 782, 112, 1, 0, 0, 0, 783, 784, 7, 13, 0, 0, 784, 785, 7, 12, 0, 0, 785, 786, 7, 2, 0, 0, 786, 787, 7, 5, 0, 0, 787, 114, 1, 0, 0, 0, 788, 789, 7, 13, 0, 0, 789, 790, 7, 1, 0, 0, 790, 791, 7, 18, 0, 0, 791, 792, 7, 3, 0, 0, 792, 116, 1, 0, 0, 0, 793, 794, 5, 40, 0, 0, 794, 118, 1, 0, 0, 0, 795, 796, 7, 9, 0, 0, 796, 797, 7, 7, 0, 0, 797, 798, 7, 5, 0, 0, 798, 120, 1, 0, 0, 0, 799, 800, 7, 9, 0, 0, 800, 801, 7, 20, 0, 0, 801, 802, 7, 13, 0, 0, 802, 803, 7, 13, 0, 0, 803, 122, 1, 0, 0, 0, 804, 805, 7, 9, 0, 0, 805, 806, 7, 20, 0, 0, 806, 807, 7, 13, 0, 0, 807, 808, 7, 13, 0, 0, 808, 809, 7, 2, 0, 0, 809, 124, 1, 0, 0, 0, 810, 811, 7, 7, 0, 0, 811, 812, 7, 6, 0, 0, 812, 126, 1, 0, 0, 0, 813, 814, 5, 63, 0, 0, 814, 128, 1, 0, 0, 0, 815, 816, 7, 6, 0, 0, 816, 817, 7, 13, 0, 0, 817, 818, 7, 1, 0, 0, 818, 819, 7, 18, 0, 0, 819, 820, 7, 3, 0, 0, 820, 130, 1, 0, 0, 0, 821, 822, 5, 41, 0, 0, 822, 132, 1, 0, 0, 0, 823, 824, 7, 5, 0, 0, 824, 825, 7, 6, 0, 0, 825, 826, 7, 20, 0, 0, 826, 827, 7, 3, 0, 0, 827, 134, 1, 0, 0, 0, 828, 829, 5, 61, 0, 0, 829, 830, 5, 61, 0, 0, 830, 136, 1, 0, 0, 0, 831, 832, 5, 61, 0, 0, 832, 833, 5, 126, 0, 0, 833, 138, 1, 0, 0, 0, 834, 835, 5, 33, 0, 0, 835, 836, 5, 61, 0, 0, 836, 140, 1, 0, 0, 0, 837, 838, 5, 60, 0, 0, 838, 142, 1, 0, 0, 0, 839, 840, 5, 60, 0, 0, 840, 841, 5, 61, 0, 0, 841, 144, 1, 0, 0, 0, 842, 843, 5, 62, 0, 0, 843, 146, 1, 0, 0, 0, 844, 845, 5, 62, 0, 0, 845, 846, 5, 61, 0, 0, 846, 148, 1, 0, 0, 0, 847, 848, 5, 43, 0, 0, 848, 150, 1, 0, 0, 0, 849, 850, 5, 45, 0, 0, 850, 152, 1, 0, 0, 0, 851, 852, 5, 42, 0, 0, 852, 154, 1, 0, 0, 0, 853, 854, 5, 47, 0, 0, 854, 156, 1, 0, 0, 0, 855, 856, 5, 37, 0, 0, 856, 158, 1, 0, 0, 0, 857, 858, 7, 16, 0, 0, 858, 859, 7, 12, 0, 0, 859, 860, 7, 5, 0, 0, 860, 861, 7, 4, 0, 0, 861, 862, 7, 10, 0, 0, 862, 160, 1, 0, 0, 0, 863, 864, 3, 45, 15, 0, 864, 865, 1, 0, 0, 0, 865, 866, 6, 73, 12, 0, 866, 162, 1, 0, 0, 0, 867, 870, 3, 127, 56, 0, 868, 871, 3, 65, 25, 0, 869, 871, 3, 79, 32, 0, 870, 868, 1, 0, 0, 0, 870, 869, 1, 0, 0, 0, 871, 875, 1, 0, 0, 0, 872, 874, 3, 81, 33, 0, 873, 872, 1, 0, 0, 0, 874, 877, 1, 0, 0, 0, 875, 873, 1, 0, 0, 0, 875, 876, 1, 0, 0, 0, 876, 885, 1, 0, 0, 0, 877, 875, 1, 0, 0, 0, 878, 880, 3, 127, 56, 0, 879, 881, 3, 63, 24, 0, 880, 879, 1, 0, 0, 0, 881, 882, 1, 0, 0, 0, 882, 880, 1, 0, 0, 0, 882, 883, 1, 0, 0, 0, 883, 885, 1, 0, 0, 0, 884, 867, 1, 0, 0, 0, 884, 878, 1, 0, 0, 0, 885, 164, 1, 0, 0, 0, 886, 887, 5, 91, 0, 0, 887, 888, 1, 0, 0, 0, 888, 889, 6, 75, 0, 0, 889, 890, 6, 75, 0, 0, 890, 166, 1, 0, 0, 0, 891, 892, 5, 93, 0, 0, 892, 893, 1, 0, 0, 0, 893, 894, 6, 76, 11, 0, 894, 895, 6, 76, 11, 0, 895, 168, 1, 0, 0, 0, 896, 900, 3, 65, 25, 0, 897, 899, 3, 81, 33, 0, 898, 897, 1, 0, 0, 0, 899, 902, 1, 0, 0, 0, 900, 898, 1, 0, 0, 0, 900, 901, 1, 0, 0, 0, 901, 913, 1, 0, 0, 0, 902, 900, 1, 0, 0, 0, 903, 906, 3, 79, 32, 0, 904, 906, 3, 73, 29, 0, 905, 903, 1, 0, 0, 0, 905, 904, 1, 0, 0, 0, 906, 908, 1, 0, 0, 0, 907, 909, 3, 81, 33, 0, 908, 907, 1, 0, 0, 0, 909, 910, 1, 0, 0, 0, 910, 908, 1, 0, 0, 0, 910, 911, 1, 0, 0, 0, 911, 913, 1, 0, 0, 0, 912, 896, 1, 0, 0, 0, 912, 905, 1, 0, 0, 0, 913, 170, 1, 0, 0, 0, 914, 916, 3, 75, 30, 0, 915, 917, 3, 77, 31, 0, 916, 915, 1, 0, 0, 0, 917, 918, 1, 0, 0, 0, 918, 916, 1, 0, 0, 0, 918, 919, 1, 0, 0, 0, 919, 920, 1, 0, 0, 0, 920, 921, 3, 75, 30, 0, 921, 172, 1, 0, 0, 0, 922, 923, 3, 171, 78, 0, 923, 174, 1, 0, 0, 0, 924, 925, 3, 55, 20, 0, 925, 926, 1, 0, 0, 0, 926, 927, 6, 80, 10, 0, 927, 176, 1, 0, 0, 0, 928, 929, 3, 57, 21, 0, 929, 930, 1, 0, 0, 0, 930, 931, 6, 81, 10, 0, 931, 178, 1, 0, 0, 0, 932, 933, 3, 59, 22, 0, 933, 934, 1, 0, 0, 0, 934, 935, 6, 82, 10, 0, 935, 180, 1, 0, 0, 0, 936, 937, 3, 165, 75, 0, 937, 938, 1, 0, 0, 0, 938, 939, 6, 83, 13, 0, 939, 940, 6, 83, 14, 0, 940, 182, 1, 0, 0, 0, 941, 942, 3, 61, 23, 0, 942, 943, 1, 0, 0, 0, 943, 944, 6, 84, 15, 0, 944, 945, 6, 84, 11, 0, 945, 184, 1, 0, 0, 0, 946, 947, 3, 59, 22, 0, 947, 948, 1, 0, 0, 0, 948, 949, 6, 85, 10, 0, 949, 186, 1, 0, 0, 0, 950, 951, 3, 55, 20, 0, 951, 952, 1, 0, 0, 0, 952, 953, 6, 86, 10, 0, 953, 188, 1, 0, 0, 0, 954, 955, 3, 57, 21, 0, 955, 956, 1, 0, 0, 0, 956, 957, 6, 87, 10, 0, 957, 190, 1, 0, 0, 0, 958, 959, 3, 61, 23, 0, 959, 960, 1, 0, 0, 0, 960, 961, 6, 88, 15, 0, 961, 962, 6, 88, 11, 0, 962, 192, 1, 0, 0, 0, 963, 964, 3, 165, 75, 0, 964, 965, 1, 0, 0, 0, 965, 966, 6, 89, 13, 0, 966, 194, 1, 0, 0, 0, 967, 968, 3, 167, 76, 0, 968, 969, 1, 0, 0, 0, 969, 970, 6, 90, 16, 0, 970, 196, 1, 0, 0, 0, 971, 972, 3, 337, 161, 0, 972, 973, 1, 0, 0, 0, 973, 974, 6, 91, 17, 0, 974, 198, 1, 0, 0, 0, 975, 976, 3, 99, 42, 0, 976, 977, 1, 0, 0, 0, 977, 978, 6, 92, 18, 0, 978, 200, 1, 0, 0, 0, 979, 980, 3, 95, 40, 0, 980, 981, 1, 0, 0, 0, 981, 982, 6, 93, 19, 0, 982, 202, 1, 0, 0, 0, 983, 984, 7, 16, 0, 0, 984, 985, 7, 3, 0, 0, 985, 986, 7, 5, 0, 0, 986, 987, 7, 12, 0, 0, 987, 988, 7, 0, 0, 0, 988, 989, 7, 12, 0, 0, 989, 990, 7, 5, 0, 0, 990, 991, 7, 12, 0, 0, 991, 204, 1, 0, 0, 0, 992, 996, 8, 32, 0, 0, 993, 994, 5, 47, 0, 0, 994, 996, 8, 33, 0, 0, 995, 992, 1, 0, 0, 0, 995, 993, 1, 0, 0, 0, 996, 206, 1, 0, 0, 0, 997, 999, 3, 205, 95, 0, 998, 997, 1, 0, 0, 0, 999, 1000, 1, 0, 0, 0, 1000, 998, 1, 0, 0, 0, 1000, 1001, 1, 0, 0, 0, 1001, 208, 1, 0, 0, 0, 1002, 1003, 3, 207, 96, 0, 1003, 1004, 1, 0, 0, 0, 1004, 1005, 6, 97, 20, 0, 1005, 210, 1, 0, 0, 0, 1006, 1007, 3, 83, 34, 0, 1007, 1008, 1, 0, 0, 0, 1008, 1009, 6, 98, 21, 0, 1009, 212, 1, 0, 0, 0, 1010, 1011, 3, 55, 20, 0, 1011, 1012, 1, 0, 0, 0, 1012, 1013, 6, 99, 10, 0, 1013, 214, 1, 0, 0, 0, 1014, 1015, 3, 57, 21, 0, 1015, 1016, 1, 0, 0, 0, 1016, 1017, 6, 100, 10, 0, 1017, 216, 1, 0, 0, 0, 1018, 1019, 3, 59, 22, 0, 1019, 1020, 1, 0, 0, 0, 1020, 1021, 6, 101, 10, 0, 1021, 218, 1, 0, 0, 0, 1022, 1023, 3, 61, 23, 0, 1023, 1024, 1, 0, 0, 0, 1024, 1025, 6, 102, 15, 0, 1025, 1026, 6, 102, 11, 0, 1026, 220, 1, 0, 0, 0, 1027, 1028, 3, 103, 44, 0, 1028, 1029, 1, 0, 0, 0, 1029, 1030, 6, 103, 22, 0, 1030, 222, 1, 0, 0, 0, 1031, 1032, 3, 99, 42, 0, 1032, 1033, 1, 0, 0, 0, 1033, 1034, 6, 104, 18, 0, 1034, 224, 1, 0, 0, 0, 1035, 1036, 4, 105, 3, 0, 1036, 1037, 3, 127, 56, 0, 1037, 1038, 1, 0, 0, 0, 1038, 1039, 6, 105, 23, 0, 1039, 226, 1, 0, 0, 0, 1040, 1041, 4, 106, 4, 0, 1041, 1042, 3, 163, 74, 0, 1042, 1043, 1, 0, 0, 0, 1043, 1044, 6, 106, 24, 0, 1044, 228, 1, 0, 0, 0, 1045, 1050, 3, 65, 25, 0, 1046, 1050, 3, 63, 24, 0, 1047, 1050, 3, 79, 32, 0, 1048, 1050, 3, 153, 69, 0, 1049, 1045, 1, 0, 0, 0, 1049, 1046, 1, 0, 0, 0, 1049, 1047, 1, 0, 0, 0, 1049, 1048, 1, 0, 0, 0, 1050, 230, 1, 0, 0, 0, 1051, 1054, 3, 65, 25, 0, 1052, 1054, 3, 153, 69, 0, 1053, 1051, 1, 0, 0, 0, 1053, 1052, 1, 0, 0, 0, 1054, 1058, 1, 0, 0, 0, 1055, 1057, 3, 229, 107, 0, 1056, 1055, 1, 0, 0, 0, 1057, 1060, 1, 0, 0, 0, 1058, 1056, 1, 0, 0, 0, 1058, 1059, 1, 0, 0, 0, 1059, 1071, 1, 0, 0, 0, 1060, 1058, 1, 0, 0, 0, 1061, 1064, 3, 79, 32, 0, 1062, 1064, 3, 73, 29, 0, 1063, 1061, 1, 0, 0, 0, 1063, 1062, 1, 0, 0, 0, 1064, 1066, 1, 0, 0, 0, 1065, 1067, 3, 229, 107, 0, 1066, 1065, 1, 0, 0, 0, 1067, 1068, 1, 0, 0, 0, 1068, 1066, 1, 0, 0, 0, 1068, 1069, 1, 0, 0, 0, 1069, 1071, 1, 0, 0, 0, 1070, 1053, 1, 0, 0, 0, 1070, 1063, 1, 0, 0, 0, 1071, 232, 1, 0, 0, 0, 1072, 1075, 3, 231, 108, 0, 1073, 1075, 3, 171, 78, 0, 1074, 1072, 1, 0, 0, 0, 1074, 1073, 1, 0, 0, 0, 1075, 1076, 1, 0, 0, 0, 1076, 1074, 1, 0, 0, 0, 1076, 1077, 1, 0, 0, 0, 1077, 234, 1, 0, 0, 0, 1078, 1079, 3, 55, 20, 0, 1079, 1080, 1, 0, 0, 0, 1080, 1081, 6, 110, 10, 0, 1081, 236, 1, 0, 0, 0, 1082, 1083, 3, 57, 21, 0, 1083, 1084, 1, 0, 0, 0, 1084, 1085, 6, 111, 10, 0, 1085, 238, 1, 0, 0, 0, 1086, 1087, 3, 59, 22, 0, 1087, 1088, 1, 0, 0, 0, 1088, 1089, 6, 112, 10, 0, 1089, 240, 1, 0, 0, 0, 1090, 1091, 3, 61, 23, 0, 1091, 1092, 1, 0, 0, 0, 1092, 1093, 6, 113, 15, 0, 1093, 1094, 6, 113, 11, 0, 1094, 242, 1, 0, 0, 0, 1095, 1096, 3, 95, 40, 0, 1096, 1097, 1, 0, 0, 0, 1097, 1098, 6, 114, 19, 0, 1098, 244, 1, 0, 0, 0, 1099, 1100, 3, 99, 42, 0, 1100, 1101, 1, 0, 0, 0, 1101, 1102, 6, 115, 18, 0, 1102, 246, 1, 0, 0, 0, 1103, 1104, 3, 103, 44, 0, 1104, 1105, 1, 0, 0, 0, 1105, 1106, 6, 116, 22, 0, 1106, 248, 1, 0, 0, 0, 1107, 1108, 4, 117, 5, 0, 1108, 1109, 3, 127, 56, 0, 1109, 1110, 1, 0, 0, 0, 1110, 1111, 6, 117, 23, 0, 1111, 250, 1, 0, 0, 0, 1112, 1113, 4, 118, 6, 0, 1113, 1114, 3, 163, 74, 0, 1114, 1115, 1, 0, 0, 0, 1115, 1116, 6, 118, 24, 0, 1116, 252, 1, 0, 0, 0, 1117, 1118, 7, 12, 0, 0, 1118, 1119, 7, 2, 0, 0, 1119, 254, 1, 0, 0, 0, 1120, 1121, 3, 233, 109, 0, 1121, 1122, 1, 0, 0, 0, 1122, 1123, 6, 120, 25, 0, 1123, 256, 1, 0, 0, 0, 1124, 1125, 3, 55, 20, 0, 1125, 1126, 1, 0, 0, 0, 1126, 1127, 6, 121, 10, 0, 1127, 258, 1, 0, 0, 0, 1128, 1129, 3, 57, 21, 0, 1129, 1130, 1, 0, 0, 0, 1130, 1131, 6, 122, 10, 0, 1131, 260, 1, 0, 0, 0, 1132, 1133, 3, 59, 22, 0, 1133, 1134, 1, 0, 0, 0, 1134, 1135, 6, 123, 10, 0, 1135, 262, 1, 0, 0, 0, 1136, 1137, 3, 61, 23, 0, 1137, 1138, 1, 0, 0, 0, 1138, 1139, 6, 124, 15, 0, 1139, 1140, 6, 124, 11, 0, 1140, 264, 1, 0, 0, 0, 1141, 1142, 3, 165, 75, 0, 1142, 1143, 1, 0, 0, 0, 1143, 1144, 6, 125, 13, 0, 1144, 1145, 6, 125, 26, 0, 1145, 266, 1, 0, 0, 0, 1146, 1147, 7, 7, 0, 0, 1147, 1148, 7, 9, 0, 0, 1148, 1149, 1, 0, 0, 0, 1149, 1150, 6, 126, 27, 0, 1150, 268, 1, 0, 0, 0, 1151, 1152, 7, 19, 0, 0, 1152, 1153, 7, 1, 0, 0, 1153, 1154, 7, 5, 0, 0, 1154, 1155, 7, 10, 0, 0, 1155, 1156, 1, 0, 0, 0, 1156, 1157, 6, 127, 27, 0, 1157, 270, 1, 0, 0, 0, 1158, 1159, 8, 34, 0, 0, 1159, 272, 1, 0, 0, 0, 1160, 1162, 3, 271, 128, 0, 1161, 1160, 1, 0, 0, 0, 1162, 1163, 1, 0, 0, 0, 1163, 1161, 1, 0, 0, 0, 1163, 1164, 1, 0, 0, 0, 1164, 1165, 1, 0, 0, 0, 1165, 1166, 3, 337, 161, 0, 1166, 1168, 1, 0, 0, 0, 1167, 1161, 1, 0, 0, 0, 1167, 1168, 1, 0, 0, 0, 1168, 1170, 1, 0, 0, 0, 1169, 1171, 3, 271, 128, 0, 1170, 1169, 1, 0, 0, 0, 1171, 1172, 1, 0, 0, 0, 1172, 1170, 1, 0, 0, 0, 1172, 1173, 1, 0, 0, 0, 1173, 274, 1, 0, 0, 0, 1174, 1175, 3, 273, 129, 0, 1175, 1176, 1, 0, 0, 0, 1176, 1177, 6, 130, 28, 0, 1177, 276, 1, 0, 0, 0, 1178, 1179, 3, 55, 20, 0, 1179, 1180, 1, 0, 0, 0, 1180, 1181, 6, 131, 10, 0, 1181, 278, 1, 0, 0, 0, 1182, 1183, 3, 57, 21, 0, 1183, 1184, 1, 0, 0, 0, 1184, 1185, 6, 132, 10, 0, 1185, 280, 1, 0, 0, 0, 1186, 1187, 3, 59, 22, 0, 1187, 1188, 1, 0, 0, 0, 1188, 1189, 6, 133, 10, 0, 1189, 282, 1, 0, 0, 0, 1190, 1191, 3, 61, 23, 0, 1191, 1192, 1, 0, 0, 0, 1192, 1193, 6, 134, 15, 0, 1193, 1194, 6, 134, 11, 0, 1194, 1195, 6, 134, 11, 0, 1195, 284, 1, 0, 0, 0, 1196, 1197, 3, 95, 40, 0, 1197, 1198, 1, 0, 0, 0, 1198, 1199, 6, 135, 19, 0, 1199, 286, 1, 0, 0, 0, 1200, 1201, 3, 99, 42, 0, 1201, 1202, 1, 0, 0, 0, 1202, 1203, 6, 136, 18, 0, 1203, 288, 1, 0, 0, 0, 1204, 1205, 3, 103, 44, 0, 1205, 1206, 1, 0, 0, 0, 1206, 1207, 6, 137, 22, 0, 1207, 290, 1, 0, 0, 0, 1208, 1209, 3, 269, 127, 0, 1209, 1210, 1, 0, 0, 0, 1210, 1211, 6, 138, 29, 0, 1211, 292, 1, 0, 0, 0, 1212, 1213, 3, 233, 109, 0, 1213, 1214, 1, 0, 0, 0, 1214, 1215, 6, 139, 25, 0, 1215, 294, 1, 0, 0, 0, 1216, 1217, 3, 173, 79, 0, 1217, 1218, 1, 0, 0, 0, 1218, 1219, 6, 140, 30, 0, 1219, 296, 1, 0, 0, 0, 1220, 1221, 4, 141, 7, 0, 1221, 1222, 3, 127, 56, 0, 1222, 1223, 1, 0, 0, 0, 1223, 1224, 6, 141, 23, 0, 1224, 298, 1, 0, 0, 0, 1225, 1226, 4, 142, 8, 0, 1226, 1227, 3, 163, 74, 0, 1227, 1228, 1, 0, 0, 0, 1228, 1229, 6, 142, 24, 0, 1229, 300, 1, 0, 0, 0, 1230, 1231, 3, 55, 20, 0, 1231, 1232, 1, 0, 0, 0, 1232, 1233, 6, 143, 10, 0, 1233, 302, 1, 0, 0, 0, 1234, 1235, 3, 57, 21, 0, 1235, 1236, 1, 0, 0, 0, 1236, 1237, 6, 144, 10, 0, 1237, 304, 1, 0, 0, 0, 1238, 1239, 3, 59, 22, 0, 1239, 1240, 1, 0, 0, 0, 1240, 1241, 6, 145, 10, 0, 1241, 306, 1, 0, 0, 0, 1242, 1243, 3, 61, 23, 0, 1243, 1244, 1, 0, 0, 0, 1244, 1245, 6, 146, 15, 0, 1245, 1246, 6, 146, 11, 0, 1246, 308, 1, 0, 0, 0, 1247, 1248, 3, 103, 44, 0, 1248, 1249, 1, 0, 0, 0, 1249, 1250, 6, 147, 22, 0, 1250, 310, 1, 0, 0, 0, 1251, 1252, 4, 148, 9, 0, 1252, 1253, 3, 127, 56, 0, 1253, 1254, 1, 0, 0, 0, 1254, 1255, 6, 148, 23, 0, 1255, 312, 1, 0, 0, 0, 1256, 1257, 4, 149, 10, 0, 1257, 1258, 3, 163, 74, 0, 1258, 1259, 1, 0, 0, 0, 1259, 1260, 6, 149, 24, 0, 1260, 314, 1, 0, 0, 0, 1261, 1262, 3, 173, 79, 0, 1262, 1263, 1, 0, 0, 0, 1263, 1264, 6, 150, 30, 0, 1264, 316, 1, 0, 0, 0, 1265, 1266, 3, 169, 77, 0, 1266, 1267, 1, 0, 0, 0, 1267, 1268, 6, 151, 31, 0, 1268, 318, 1, 0, 0, 0, 1269, 1270, 3, 55, 20, 0, 1270, 1271, 1, 0, 0, 0, 1271, 1272, 6, 152, 10, 0, 1272, 320, 1, 0, 0, 0, 1273, 1274, 3, 57, 21, 0, 1274, 1275, 1, 0, 0, 0, 1275, 1276, 6, 153, 10, 0, 1276, 322, 1, 0, 0, 0, 1277, 1278, 3, 59, 22, 0, 1278, 1279, 1, 0, 0, 0, 1279, 1280, 6, 154, 10, 0, 1280, 324, 1, 0, 0, 0, 1281, 1282, 3, 61, 23, 0, 1282, 1283, 1, 0, 0, 0, 1283, 1284, 6, 155, 15, 0, 1284, 1285, 6, 155, 11, 0, 1285, 326, 1, 0, 0, 0, 1286, 1287, 7, 1, 0, 0, 1287, 1288, 7, 9, 0, 0, 1288, 1289, 7, 15, 0, 0, 1289, 1290, 7, 7, 0, 0, 1290, 328, 1, 0, 0, 0, 1291, 1292, 3, 55, 20, 0, 1292, 1293, 1, 0, 0, 0, 1293, 1294, 6, 157, 10, 0, 1294, 330, 1, 0, 0, 0, 1295, 1296, 3, 57, 21, 0, 1296, 1297, 1, 0, 0, 0, 1297, 1298, 6, 158, 10, 0, 1298, 332, 1, 0, 0, 0, 1299, 1300, 3, 59, 22, 0, 1300, 1301, 1, 0, 0, 0, 1301, 1302, 6, 159, 10, 0, 1302, 334, 1, 0, 0, 0, 1303, 1304, 3, 167, 76, 0, 1304, 1305, 1, 0, 0, 0, 1305, 1306, 6, 160, 16, 0, 1306, 1307, 6, 160, 11, 0, 1307, 336, 1, 0, 0, 0, 1308, 1309, 5, 58, 0, 0, 1309, 338, 1, 0, 0, 0, 1310, 1316, 3, 73, 29, 0, 1311, 1316, 3, 63, 24, 0, 1312, 1316, 3, 103, 44, 0, 1313, 1316, 3, 65, 25, 0, 1314, 1316, 3, 79, 32, 0, 1315, 1310, 1, 0, 0, 0, 1315, 1311, 1, 0, 0, 0, 1315, 1312, 1, 0, 0, 0, 1315, 1313, 1, 0, 0, 0, 1315, 1314, 1, 0, 0, 0, 1316, 1317, 1, 0, 0, 0, 1317, 1315, 1, 0, 0, 0, 1317, 1318, 1, 0, 0, 0, 1318, 340, 1, 0, 0, 0, 1319, 1320, 3, 55, 20, 0, 1320, 1321, 1, 0, 0, 0, 1321, 1322, 6, 163, 10, 0, 1322, 342, 1, 0, 0, 0, 1323, 1324, 3, 57, 21, 0, 1324, 1325, 1, 0, 0, 0, 1325, 1326, 6, 164, 10, 0, 1326, 344, 1, 0, 0, 0, 1327, 1328, 3, 59, 22, 0, 1328, 1329, 1, 0, 0, 0, 1329, 1330, 6, 165, 10, 0, 1330, 346, 1, 0, 0, 0, 1331, 1332, 3, 61, 23, 0, 1332, 1333, 1, 0, 0, 0, 1333, 1334, 6, 166, 15, 0, 1334, 1335, 6, 166, 11, 0, 1335, 348, 1, 0, 0, 0, 1336, 1337, 3, 337, 161, 0, 1337, 1338, 1, 0, 0, 0, 1338, 1339, 6, 167, 17, 0, 1339, 350, 1, 0, 0, 0, 1340, 1341, 3, 99, 42, 0, 1341, 1342, 1, 0, 0, 0, 1342, 1343, 6, 168, 18, 0, 1343, 352, 1, 0, 0, 0, 1344, 1345, 3, 103, 44, 0, 1345, 1346, 1, 0, 0, 0, 1346, 1347, 6, 169, 22, 0, 1347, 354, 1, 0, 0, 0, 1348, 1349, 3, 267, 126, 0, 1349, 1350, 1, 0, 0, 0, 1350, 1351, 6, 170, 32, 0, 1351, 1352, 6, 170, 33, 0, 1352, 356, 1, 0, 0, 0, 1353, 1354, 3, 207, 96, 0, 1354, 1355, 1, 0, 0, 0, 1355, 1356, 6, 171, 20, 0, 1356, 358, 1, 0, 0, 0, 1357, 1358, 3, 83, 34, 0, 1358, 1359, 1, 0, 0, 0, 1359, 1360, 6, 172, 21, 0, 1360, 360, 1, 0, 0, 0, 1361, 1362, 3, 55, 20, 0, 1362, 1363, 1, 0, 0, 0, 1363, 1364, 6, 173, 10, 0, 1364, 362, 1, 0, 0, 0, 1365, 1366, 3, 57, 21, 0, 1366, 1367, 1, 0, 0, 0, 1367, 1368, 6, 174, 10, 0, 1368, 364, 1, 0, 0, 0, 1369, 1370, 3, 59, 22, 0, 1370, 1371, 1, 0, 0, 0, 1371, 1372, 6, 175, 10, 0, 1372, 366, 1, 0, 0, 0, 1373, 1374, 3, 61, 23, 0, 1374, 1375, 1, 0, 0, 0, 1375, 1376, 6, 176, 15, 0, 1376, 1377, 6, 176, 11, 0, 1377, 1378, 6, 176, 11, 0, 1378, 368, 1, 0, 0, 0, 1379, 1380, 3, 99, 42, 0, 1380, 1381, 1, 0, 0, 0, 1381, 1382, 6, 177, 18, 0, 1382, 370, 1, 0, 0, 0, 1383, 1384, 3, 103, 44, 0, 1384, 1385, 1, 0, 0, 0, 1385, 1386, 6, 178, 22, 0, 1386, 372, 1, 0, 0, 0, 1387, 1388, 3, 233, 109, 0, 1388, 1389, 1, 0, 0, 0, 1389, 1390, 6, 179, 25, 0, 1390, 374, 1, 0, 0, 0, 1391, 1392, 3, 55, 20, 0, 1392, 1393, 1, 0, 0, 0, 1393, 1394, 6, 180, 10, 0, 1394, 376, 1, 0, 0, 0, 1395, 1396, 3, 57, 21, 0, 1396, 1397, 1, 0, 0, 0, 1397, 1398, 6, 181, 10, 0, 1398, 378, 1, 0, 0, 0, 1399, 1400, 3, 59, 22, 0, 1400, 1401, 1, 0, 0, 0, 1401, 1402, 6, 182, 10, 0, 1402, 380, 1, 0, 0, 0, 1403, 1404, 3, 61, 23, 0, 1404, 1405, 1, 0, 0, 0, 1405, 1406, 6, 183, 15, 0, 1406, 1407, 6, 183, 11, 0, 1407, 382, 1, 0, 0, 0, 1408, 1409, 3, 207, 96, 0, 1409, 1410, 1, 0, 0, 0, 1410, 1411, 6, 184, 20, 0, 1411, 1412, 6, 184, 11, 0, 1412, 1413, 6, 184, 34, 0, 1413, 384, 1, 0, 0, 0, 1414, 1415, 3, 83, 34, 0, 1415, 1416, 1, 0, 0, 0, 1416, 1417, 6, 185, 21, 0, 1417, 1418, 6, 185, 11, 0, 1418, 1419, 6, 185, 34, 0, 1419, 386, 1, 0, 0, 0, 1420, 1421, 3, 55, 20, 0, 1421, 1422, 1, 0, 0, 0, 1422, 1423, 6, 186, 10, 0, 1423, 388, 1, 0, 0, 0, 1424, 1425, 3, 57, 21, 0, 1425, 1426, 1, 0, 0, 0, 1426, 1427, 6, 187, 10, 0, 1427, 390, 1, 0, 0, 0, 1428, 1429, 3, 59, 22, 0, 1429, 1430, 1, 0, 0, 0, 1430, 1431, 6, 188, 10, 0, 1431, 392, 1, 0, 0, 0, 1432, 1433, 3, 337, 161, 0, 1433, 1434, 1, 0, 0, 0, 1434, 1435, 6, 189, 17, 0, 1435, 1436, 6, 189, 11, 0, 1436, 1437, 6, 189, 9, 0, 1437, 394, 1, 0, 0, 0, 1438, 1439, 3, 99, 42, 0, 1439, 1440, 1, 0, 0, 0, 1440, 1441, 6, 190, 18, 0, 1441, 1442, 6, 190, 11, 0, 1442, 1443, 6, 190, 9, 0, 1443, 396, 1, 0, 0, 0, 1444, 1445, 3, 55, 20, 0, 1445, 1446, 1, 0, 0, 0, 1446, 1447, 6, 191, 10, 0, 1447, 398, 1, 0, 0, 0, 1448, 1449, 3, 57, 21, 0, 1449, 1450, 1, 0, 0, 0, 1450, 1451, 6, 192, 10, 0, 1451, 400, 1, 0, 0, 0, 1452, 1453, 3, 59, 22, 0, 1453, 1454, 1, 0, 0, 0, 1454, 1455, 6, 193, 10, 0, 1455, 402, 1, 0, 0, 0, 1456, 1457, 3, 173, 79, 0, 1457, 1458, 1, 0, 0, 0, 1458, 1459, 6, 194, 11, 0, 1459, 1460, 6, 194, 0, 0, 1460, 1461, 6, 194, 30, 0, 1461, 404, 1, 0, 0, 0, 1462, 1463, 3, 169, 77, 0, 1463, 1464, 1, 0, 0, 0, 1464, 1465, 6, 195, 11, 0, 1465, 1466, 6, 195, 0, 0, 1466, 1467, 6, 195, 31, 0, 1467, 406, 1, 0, 0, 0, 1468, 1469, 3, 89, 37, 0, 1469, 1470, 1, 0, 0, 0, 1470, 1471, 6, 196, 11, 0, 1471, 1472, 6, 196, 0, 0, 1472, 1473, 6, 196, 35, 0, 1473, 408, 1, 0, 0, 0, 1474, 1475, 3, 61, 23, 0, 1475, 1476, 1, 0, 0, 0, 1476, 1477, 6, 197, 15, 0, 1477, 1478, 6, 197, 11, 0, 1478, 410, 1, 0, 0, 0, 65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 579, 589, 593, 596, 605, 607, 618, 637, 642, 651, 658, 663, 665, 676, 684, 687, 689, 694, 699, 705, 712, 717, 723, 726, 734, 738, 870, 875, 882, 884, 900, 905, 910, 912, 918, 995, 1000, 1049, 1053, 1058, 1063, 1068, 1070, 1074, 1076, 1163, 1167, 1172, 1315, 1317, 36, 5, 1, 0, 5, 4, 0, 5, 6, 0, 5, 2, 0, 5, 3, 0, 5, 8, 0, 5, 5, 0, 5, 9, 0, 5, 11, 0, 5, 13, 0, 0, 1, 0, 4, 0, 0, 7, 16, 0, 7, 65, 0, 5, 0, 0, 7, 24, 0, 7, 66, 0, 7, 104, 0, 7, 33, 0, 7, 31, 0, 7, 76, 0, 7, 25, 0, 7, 35, 0, 7, 47, 0, 7, 64, 0, 7, 80, 0, 5, 10, 0, 5, 7, 0, 7, 90, 0, 7, 89, 0, 7, 68, 0, 7, 67, 0, 7, 88, 0, 5, 12, 0, 5, 14, 0, 7, 28, 0] \ No newline at end of file +[4, 0, 119, 1484, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139, 2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144, 7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148, 2, 149, 7, 149, 2, 150, 7, 150, 2, 151, 7, 151, 2, 152, 7, 152, 2, 153, 7, 153, 2, 154, 7, 154, 2, 155, 7, 155, 2, 156, 7, 156, 2, 157, 7, 157, 2, 158, 7, 158, 2, 159, 7, 159, 2, 160, 7, 160, 2, 161, 7, 161, 2, 162, 7, 162, 2, 163, 7, 163, 2, 164, 7, 164, 2, 165, 7, 165, 2, 166, 7, 166, 2, 167, 7, 167, 2, 168, 7, 168, 2, 169, 7, 169, 2, 170, 7, 170, 2, 171, 7, 171, 2, 172, 7, 172, 2, 173, 7, 173, 2, 174, 7, 174, 2, 175, 7, 175, 2, 176, 7, 176, 2, 177, 7, 177, 2, 178, 7, 178, 2, 179, 7, 179, 2, 180, 7, 180, 2, 181, 7, 181, 2, 182, 7, 182, 2, 183, 7, 183, 2, 184, 7, 184, 2, 185, 7, 185, 2, 186, 7, 186, 2, 187, 7, 187, 2, 188, 7, 188, 2, 189, 7, 189, 2, 190, 7, 190, 2, 191, 7, 191, 2, 192, 7, 192, 2, 193, 7, 193, 2, 194, 7, 194, 2, 195, 7, 195, 2, 196, 7, 196, 2, 197, 7, 197, 2, 198, 7, 198, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 4, 19, 580, 8, 19, 11, 19, 12, 19, 581, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 5, 20, 590, 8, 20, 10, 20, 12, 20, 593, 9, 20, 1, 20, 3, 20, 596, 8, 20, 1, 20, 3, 20, 599, 8, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 5, 21, 608, 8, 21, 10, 21, 12, 21, 611, 9, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 4, 22, 619, 8, 22, 11, 22, 12, 22, 620, 1, 22, 1, 22, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 29, 1, 29, 3, 29, 642, 8, 29, 1, 29, 4, 29, 645, 8, 29, 11, 29, 12, 29, 646, 1, 30, 1, 30, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 3, 32, 656, 8, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 3, 34, 663, 8, 34, 1, 35, 1, 35, 1, 35, 5, 35, 668, 8, 35, 10, 35, 12, 35, 671, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 679, 8, 35, 10, 35, 12, 35, 682, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 3, 35, 689, 8, 35, 1, 35, 3, 35, 692, 8, 35, 3, 35, 694, 8, 35, 1, 36, 4, 36, 697, 8, 36, 11, 36, 12, 36, 698, 1, 37, 4, 37, 702, 8, 37, 11, 37, 12, 37, 703, 1, 37, 1, 37, 5, 37, 708, 8, 37, 10, 37, 12, 37, 711, 9, 37, 1, 37, 1, 37, 4, 37, 715, 8, 37, 11, 37, 12, 37, 716, 1, 37, 4, 37, 720, 8, 37, 11, 37, 12, 37, 721, 1, 37, 1, 37, 5, 37, 726, 8, 37, 10, 37, 12, 37, 729, 9, 37, 3, 37, 731, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 4, 37, 737, 8, 37, 11, 37, 12, 37, 738, 1, 37, 1, 37, 3, 37, 743, 8, 37, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 69, 1, 69, 1, 70, 1, 70, 1, 71, 1, 71, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 3, 75, 874, 8, 75, 1, 75, 5, 75, 877, 8, 75, 10, 75, 12, 75, 880, 9, 75, 1, 75, 1, 75, 4, 75, 884, 8, 75, 11, 75, 12, 75, 885, 3, 75, 888, 8, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 5, 78, 902, 8, 78, 10, 78, 12, 78, 905, 9, 78, 1, 78, 1, 78, 3, 78, 909, 8, 78, 1, 78, 4, 78, 912, 8, 78, 11, 78, 12, 78, 913, 3, 78, 916, 8, 78, 1, 79, 1, 79, 4, 79, 920, 8, 79, 11, 79, 12, 79, 921, 1, 79, 1, 79, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 1, 88, 1, 88, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 96, 3, 96, 999, 8, 96, 1, 97, 4, 97, 1002, 8, 97, 11, 97, 12, 97, 1003, 1, 98, 1, 98, 1, 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 102, 1, 102, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 104, 1, 104, 1, 104, 1, 104, 1, 105, 1, 105, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 108, 1, 108, 1, 108, 1, 108, 3, 108, 1053, 8, 108, 1, 109, 1, 109, 3, 109, 1057, 8, 109, 1, 109, 5, 109, 1060, 8, 109, 10, 109, 12, 109, 1063, 9, 109, 1, 109, 1, 109, 3, 109, 1067, 8, 109, 1, 109, 4, 109, 1070, 8, 109, 11, 109, 12, 109, 1071, 3, 109, 1074, 8, 109, 1, 110, 1, 110, 4, 110, 1078, 8, 110, 11, 110, 12, 110, 1079, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1, 115, 1, 115, 1, 116, 1, 116, 1, 116, 1, 116, 1, 117, 1, 117, 1, 117, 1, 117, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 121, 1, 121, 1, 122, 1, 122, 1, 122, 1, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 126, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1, 127, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 129, 1, 129, 1, 130, 4, 130, 1165, 8, 130, 11, 130, 12, 130, 1166, 1, 130, 1, 130, 3, 130, 1171, 8, 130, 1, 130, 4, 130, 1174, 8, 130, 11, 130, 12, 130, 1175, 1, 131, 1, 131, 1, 131, 1, 131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 133, 1, 133, 1, 133, 1, 133, 1, 134, 1, 134, 1, 134, 1, 134, 1, 135, 1, 135, 1, 135, 1, 135, 1, 135, 1, 135, 1, 136, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 137, 1, 137, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 1, 142, 1, 143, 1, 143, 1, 143, 1, 143, 1, 143, 1, 144, 1, 144, 1, 144, 1, 144, 1, 145, 1, 145, 1, 145, 1, 145, 1, 146, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 148, 1, 148, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1, 151, 1, 151, 1, 152, 1, 152, 1, 152, 1, 152, 1, 153, 1, 153, 1, 153, 1, 153, 1, 154, 1, 154, 1, 154, 1, 154, 1, 155, 1, 155, 1, 155, 1, 155, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 1, 157, 1, 157, 1, 157, 1, 157, 1, 157, 1, 158, 1, 158, 1, 158, 1, 158, 1, 159, 1, 159, 1, 159, 1, 159, 1, 160, 1, 160, 1, 160, 1, 160, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 163, 1, 163, 1, 163, 1, 163, 1, 163, 4, 163, 1321, 8, 163, 11, 163, 12, 163, 1322, 1, 164, 1, 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1, 165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 167, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1, 168, 1, 168, 1, 168, 1, 169, 1, 169, 1, 169, 1, 169, 1, 170, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 171, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 173, 1, 173, 1, 173, 1, 173, 1, 174, 1, 174, 1, 174, 1, 174, 1, 175, 1, 175, 1, 175, 1, 175, 1, 176, 1, 176, 1, 176, 1, 176, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 1, 178, 1, 178, 1, 178, 1, 178, 1, 179, 1, 179, 1, 179, 1, 179, 1, 180, 1, 180, 1, 180, 1, 180, 1, 181, 1, 181, 1, 181, 1, 181, 1, 182, 1, 182, 1, 182, 1, 182, 1, 183, 1, 183, 1, 183, 1, 183, 1, 184, 1, 184, 1, 184, 1, 184, 1, 184, 1, 185, 1, 185, 1, 185, 1, 185, 1, 185, 1, 185, 1, 186, 1, 186, 1, 186, 1, 186, 1, 186, 1, 186, 1, 187, 1, 187, 1, 187, 1, 187, 1, 188, 1, 188, 1, 188, 1, 188, 1, 189, 1, 189, 1, 189, 1, 189, 1, 190, 1, 190, 1, 190, 1, 190, 1, 190, 1, 190, 1, 191, 1, 191, 1, 191, 1, 191, 1, 191, 1, 191, 1, 192, 1, 192, 1, 192, 1, 192, 1, 193, 1, 193, 1, 193, 1, 193, 1, 194, 1, 194, 1, 194, 1, 194, 1, 195, 1, 195, 1, 195, 1, 195, 1, 195, 1, 195, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 197, 1, 197, 1, 197, 1, 197, 1, 197, 1, 197, 1, 198, 1, 198, 1, 198, 1, 198, 1, 198, 2, 609, 680, 0, 199, 15, 1, 17, 2, 19, 3, 21, 4, 23, 5, 25, 6, 27, 7, 29, 8, 31, 9, 33, 10, 35, 11, 37, 12, 39, 13, 41, 14, 43, 15, 45, 16, 47, 17, 49, 18, 51, 19, 53, 20, 55, 21, 57, 22, 59, 23, 61, 24, 63, 25, 65, 0, 67, 0, 69, 0, 71, 0, 73, 0, 75, 0, 77, 0, 79, 0, 81, 0, 83, 0, 85, 26, 87, 27, 89, 28, 91, 29, 93, 30, 95, 31, 97, 32, 99, 33, 101, 34, 103, 35, 105, 36, 107, 37, 109, 38, 111, 39, 113, 40, 115, 41, 117, 42, 119, 43, 121, 44, 123, 45, 125, 46, 127, 47, 129, 48, 131, 49, 133, 50, 135, 51, 137, 52, 139, 53, 141, 54, 143, 55, 145, 56, 147, 57, 149, 58, 151, 59, 153, 60, 155, 61, 157, 62, 159, 63, 161, 0, 163, 0, 165, 64, 167, 65, 169, 66, 171, 67, 173, 0, 175, 68, 177, 69, 179, 70, 181, 71, 183, 0, 185, 0, 187, 72, 189, 73, 191, 74, 193, 0, 195, 0, 197, 0, 199, 0, 201, 0, 203, 0, 205, 75, 207, 0, 209, 76, 211, 0, 213, 0, 215, 77, 217, 78, 219, 79, 221, 0, 223, 0, 225, 0, 227, 0, 229, 0, 231, 0, 233, 0, 235, 80, 237, 81, 239, 82, 241, 83, 243, 0, 245, 0, 247, 0, 249, 0, 251, 0, 253, 0, 255, 84, 257, 0, 259, 85, 261, 86, 263, 87, 265, 0, 267, 0, 269, 88, 271, 89, 273, 0, 275, 90, 277, 0, 279, 91, 281, 92, 283, 93, 285, 0, 287, 0, 289, 0, 291, 0, 293, 0, 295, 0, 297, 0, 299, 0, 301, 0, 303, 94, 305, 95, 307, 96, 309, 0, 311, 0, 313, 0, 315, 0, 317, 0, 319, 0, 321, 97, 323, 98, 325, 99, 327, 0, 329, 100, 331, 101, 333, 102, 335, 103, 337, 0, 339, 0, 341, 104, 343, 105, 345, 106, 347, 107, 349, 0, 351, 0, 353, 0, 355, 0, 357, 0, 359, 0, 361, 0, 363, 108, 365, 109, 367, 110, 369, 0, 371, 0, 373, 0, 375, 0, 377, 111, 379, 112, 381, 113, 383, 0, 385, 0, 387, 0, 389, 114, 391, 115, 393, 116, 395, 0, 397, 0, 399, 117, 401, 118, 403, 119, 405, 0, 407, 0, 409, 0, 411, 0, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 35, 2, 0, 68, 68, 100, 100, 2, 0, 73, 73, 105, 105, 2, 0, 83, 83, 115, 115, 2, 0, 69, 69, 101, 101, 2, 0, 67, 67, 99, 99, 2, 0, 84, 84, 116, 116, 2, 0, 82, 82, 114, 114, 2, 0, 79, 79, 111, 111, 2, 0, 80, 80, 112, 112, 2, 0, 78, 78, 110, 110, 2, 0, 72, 72, 104, 104, 2, 0, 86, 86, 118, 118, 2, 0, 65, 65, 97, 97, 2, 0, 76, 76, 108, 108, 2, 0, 88, 88, 120, 120, 2, 0, 70, 70, 102, 102, 2, 0, 77, 77, 109, 109, 2, 0, 71, 71, 103, 103, 2, 0, 75, 75, 107, 107, 2, 0, 87, 87, 119, 119, 2, 0, 85, 85, 117, 117, 6, 0, 9, 10, 13, 13, 32, 32, 47, 47, 91, 91, 93, 93, 2, 0, 10, 10, 13, 13, 3, 0, 9, 10, 13, 13, 32, 32, 1, 0, 48, 57, 2, 0, 65, 90, 97, 122, 8, 0, 34, 34, 78, 78, 82, 82, 84, 84, 92, 92, 110, 110, 114, 114, 116, 116, 4, 0, 10, 10, 13, 13, 34, 34, 92, 92, 2, 0, 43, 43, 45, 45, 1, 0, 96, 96, 2, 0, 66, 66, 98, 98, 2, 0, 89, 89, 121, 121, 11, 0, 9, 10, 13, 13, 32, 32, 34, 34, 44, 44, 47, 47, 58, 58, 61, 61, 91, 91, 93, 93, 124, 124, 2, 0, 42, 42, 47, 47, 11, 0, 9, 10, 13, 13, 32, 32, 34, 35, 44, 44, 47, 47, 58, 58, 60, 60, 62, 63, 92, 92, 124, 124, 1512, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 1, 63, 1, 0, 0, 0, 1, 85, 1, 0, 0, 0, 1, 87, 1, 0, 0, 0, 1, 89, 1, 0, 0, 0, 1, 91, 1, 0, 0, 0, 1, 93, 1, 0, 0, 0, 1, 95, 1, 0, 0, 0, 1, 97, 1, 0, 0, 0, 1, 99, 1, 0, 0, 0, 1, 101, 1, 0, 0, 0, 1, 103, 1, 0, 0, 0, 1, 105, 1, 0, 0, 0, 1, 107, 1, 0, 0, 0, 1, 109, 1, 0, 0, 0, 1, 111, 1, 0, 0, 0, 1, 113, 1, 0, 0, 0, 1, 115, 1, 0, 0, 0, 1, 117, 1, 0, 0, 0, 1, 119, 1, 0, 0, 0, 1, 121, 1, 0, 0, 0, 1, 123, 1, 0, 0, 0, 1, 125, 1, 0, 0, 0, 1, 127, 1, 0, 0, 0, 1, 129, 1, 0, 0, 0, 1, 131, 1, 0, 0, 0, 1, 133, 1, 0, 0, 0, 1, 135, 1, 0, 0, 0, 1, 137, 1, 0, 0, 0, 1, 139, 1, 0, 0, 0, 1, 141, 1, 0, 0, 0, 1, 143, 1, 0, 0, 0, 1, 145, 1, 0, 0, 0, 1, 147, 1, 0, 0, 0, 1, 149, 1, 0, 0, 0, 1, 151, 1, 0, 0, 0, 1, 153, 1, 0, 0, 0, 1, 155, 1, 0, 0, 0, 1, 157, 1, 0, 0, 0, 1, 159, 1, 0, 0, 0, 1, 161, 1, 0, 0, 0, 1, 163, 1, 0, 0, 0, 1, 165, 1, 0, 0, 0, 1, 167, 1, 0, 0, 0, 1, 169, 1, 0, 0, 0, 1, 171, 1, 0, 0, 0, 1, 175, 1, 0, 0, 0, 1, 177, 1, 0, 0, 0, 1, 179, 1, 0, 0, 0, 1, 181, 1, 0, 0, 0, 2, 183, 1, 0, 0, 0, 2, 185, 1, 0, 0, 0, 2, 187, 1, 0, 0, 0, 2, 189, 1, 0, 0, 0, 2, 191, 1, 0, 0, 0, 3, 193, 1, 0, 0, 0, 3, 195, 1, 0, 0, 0, 3, 197, 1, 0, 0, 0, 3, 199, 1, 0, 0, 0, 3, 201, 1, 0, 0, 0, 3, 203, 1, 0, 0, 0, 3, 205, 1, 0, 0, 0, 3, 209, 1, 0, 0, 0, 3, 211, 1, 0, 0, 0, 3, 213, 1, 0, 0, 0, 3, 215, 1, 0, 0, 0, 3, 217, 1, 0, 0, 0, 3, 219, 1, 0, 0, 0, 4, 221, 1, 0, 0, 0, 4, 223, 1, 0, 0, 0, 4, 225, 1, 0, 0, 0, 4, 227, 1, 0, 0, 0, 4, 229, 1, 0, 0, 0, 4, 235, 1, 0, 0, 0, 4, 237, 1, 0, 0, 0, 4, 239, 1, 0, 0, 0, 4, 241, 1, 0, 0, 0, 5, 243, 1, 0, 0, 0, 5, 245, 1, 0, 0, 0, 5, 247, 1, 0, 0, 0, 5, 249, 1, 0, 0, 0, 5, 251, 1, 0, 0, 0, 5, 253, 1, 0, 0, 0, 5, 255, 1, 0, 0, 0, 5, 257, 1, 0, 0, 0, 5, 259, 1, 0, 0, 0, 5, 261, 1, 0, 0, 0, 5, 263, 1, 0, 0, 0, 6, 265, 1, 0, 0, 0, 6, 267, 1, 0, 0, 0, 6, 269, 1, 0, 0, 0, 6, 271, 1, 0, 0, 0, 6, 275, 1, 0, 0, 0, 6, 277, 1, 0, 0, 0, 6, 279, 1, 0, 0, 0, 6, 281, 1, 0, 0, 0, 6, 283, 1, 0, 0, 0, 7, 285, 1, 0, 0, 0, 7, 287, 1, 0, 0, 0, 7, 289, 1, 0, 0, 0, 7, 291, 1, 0, 0, 0, 7, 293, 1, 0, 0, 0, 7, 295, 1, 0, 0, 0, 7, 297, 1, 0, 0, 0, 7, 299, 1, 0, 0, 0, 7, 301, 1, 0, 0, 0, 7, 303, 1, 0, 0, 0, 7, 305, 1, 0, 0, 0, 7, 307, 1, 0, 0, 0, 8, 309, 1, 0, 0, 0, 8, 311, 1, 0, 0, 0, 8, 313, 1, 0, 0, 0, 8, 315, 1, 0, 0, 0, 8, 317, 1, 0, 0, 0, 8, 319, 1, 0, 0, 0, 8, 321, 1, 0, 0, 0, 8, 323, 1, 0, 0, 0, 8, 325, 1, 0, 0, 0, 9, 327, 1, 0, 0, 0, 9, 329, 1, 0, 0, 0, 9, 331, 1, 0, 0, 0, 9, 333, 1, 0, 0, 0, 9, 335, 1, 0, 0, 0, 10, 337, 1, 0, 0, 0, 10, 339, 1, 0, 0, 0, 10, 341, 1, 0, 0, 0, 10, 343, 1, 0, 0, 0, 10, 345, 1, 0, 0, 0, 10, 347, 1, 0, 0, 0, 11, 349, 1, 0, 0, 0, 11, 351, 1, 0, 0, 0, 11, 353, 1, 0, 0, 0, 11, 355, 1, 0, 0, 0, 11, 357, 1, 0, 0, 0, 11, 359, 1, 0, 0, 0, 11, 361, 1, 0, 0, 0, 11, 363, 1, 0, 0, 0, 11, 365, 1, 0, 0, 0, 11, 367, 1, 0, 0, 0, 12, 369, 1, 0, 0, 0, 12, 371, 1, 0, 0, 0, 12, 373, 1, 0, 0, 0, 12, 375, 1, 0, 0, 0, 12, 377, 1, 0, 0, 0, 12, 379, 1, 0, 0, 0, 12, 381, 1, 0, 0, 0, 13, 383, 1, 0, 0, 0, 13, 385, 1, 0, 0, 0, 13, 387, 1, 0, 0, 0, 13, 389, 1, 0, 0, 0, 13, 391, 1, 0, 0, 0, 13, 393, 1, 0, 0, 0, 14, 395, 1, 0, 0, 0, 14, 397, 1, 0, 0, 0, 14, 399, 1, 0, 0, 0, 14, 401, 1, 0, 0, 0, 14, 403, 1, 0, 0, 0, 14, 405, 1, 0, 0, 0, 14, 407, 1, 0, 0, 0, 14, 409, 1, 0, 0, 0, 14, 411, 1, 0, 0, 0, 15, 413, 1, 0, 0, 0, 17, 423, 1, 0, 0, 0, 19, 430, 1, 0, 0, 0, 21, 439, 1, 0, 0, 0, 23, 446, 1, 0, 0, 0, 25, 456, 1, 0, 0, 0, 27, 463, 1, 0, 0, 0, 29, 470, 1, 0, 0, 0, 31, 477, 1, 0, 0, 0, 33, 485, 1, 0, 0, 0, 35, 497, 1, 0, 0, 0, 37, 506, 1, 0, 0, 0, 39, 512, 1, 0, 0, 0, 41, 519, 1, 0, 0, 0, 43, 526, 1, 0, 0, 0, 45, 534, 1, 0, 0, 0, 47, 542, 1, 0, 0, 0, 49, 557, 1, 0, 0, 0, 51, 567, 1, 0, 0, 0, 53, 579, 1, 0, 0, 0, 55, 585, 1, 0, 0, 0, 57, 602, 1, 0, 0, 0, 59, 618, 1, 0, 0, 0, 61, 624, 1, 0, 0, 0, 63, 626, 1, 0, 0, 0, 65, 630, 1, 0, 0, 0, 67, 632, 1, 0, 0, 0, 69, 634, 1, 0, 0, 0, 71, 637, 1, 0, 0, 0, 73, 639, 1, 0, 0, 0, 75, 648, 1, 0, 0, 0, 77, 650, 1, 0, 0, 0, 79, 655, 1, 0, 0, 0, 81, 657, 1, 0, 0, 0, 83, 662, 1, 0, 0, 0, 85, 693, 1, 0, 0, 0, 87, 696, 1, 0, 0, 0, 89, 742, 1, 0, 0, 0, 91, 744, 1, 0, 0, 0, 93, 747, 1, 0, 0, 0, 95, 751, 1, 0, 0, 0, 97, 755, 1, 0, 0, 0, 99, 757, 1, 0, 0, 0, 101, 760, 1, 0, 0, 0, 103, 762, 1, 0, 0, 0, 105, 767, 1, 0, 0, 0, 107, 769, 1, 0, 0, 0, 109, 775, 1, 0, 0, 0, 111, 781, 1, 0, 0, 0, 113, 784, 1, 0, 0, 0, 115, 787, 1, 0, 0, 0, 117, 792, 1, 0, 0, 0, 119, 797, 1, 0, 0, 0, 121, 799, 1, 0, 0, 0, 123, 803, 1, 0, 0, 0, 125, 808, 1, 0, 0, 0, 127, 814, 1, 0, 0, 0, 129, 817, 1, 0, 0, 0, 131, 819, 1, 0, 0, 0, 133, 825, 1, 0, 0, 0, 135, 827, 1, 0, 0, 0, 137, 832, 1, 0, 0, 0, 139, 835, 1, 0, 0, 0, 141, 838, 1, 0, 0, 0, 143, 841, 1, 0, 0, 0, 145, 843, 1, 0, 0, 0, 147, 846, 1, 0, 0, 0, 149, 848, 1, 0, 0, 0, 151, 851, 1, 0, 0, 0, 153, 853, 1, 0, 0, 0, 155, 855, 1, 0, 0, 0, 157, 857, 1, 0, 0, 0, 159, 859, 1, 0, 0, 0, 161, 861, 1, 0, 0, 0, 163, 866, 1, 0, 0, 0, 165, 887, 1, 0, 0, 0, 167, 889, 1, 0, 0, 0, 169, 894, 1, 0, 0, 0, 171, 915, 1, 0, 0, 0, 173, 917, 1, 0, 0, 0, 175, 925, 1, 0, 0, 0, 177, 927, 1, 0, 0, 0, 179, 931, 1, 0, 0, 0, 181, 935, 1, 0, 0, 0, 183, 939, 1, 0, 0, 0, 185, 944, 1, 0, 0, 0, 187, 949, 1, 0, 0, 0, 189, 953, 1, 0, 0, 0, 191, 957, 1, 0, 0, 0, 193, 961, 1, 0, 0, 0, 195, 966, 1, 0, 0, 0, 197, 970, 1, 0, 0, 0, 199, 974, 1, 0, 0, 0, 201, 978, 1, 0, 0, 0, 203, 982, 1, 0, 0, 0, 205, 986, 1, 0, 0, 0, 207, 998, 1, 0, 0, 0, 209, 1001, 1, 0, 0, 0, 211, 1005, 1, 0, 0, 0, 213, 1009, 1, 0, 0, 0, 215, 1013, 1, 0, 0, 0, 217, 1017, 1, 0, 0, 0, 219, 1021, 1, 0, 0, 0, 221, 1025, 1, 0, 0, 0, 223, 1030, 1, 0, 0, 0, 225, 1034, 1, 0, 0, 0, 227, 1038, 1, 0, 0, 0, 229, 1043, 1, 0, 0, 0, 231, 1052, 1, 0, 0, 0, 233, 1073, 1, 0, 0, 0, 235, 1077, 1, 0, 0, 0, 237, 1081, 1, 0, 0, 0, 239, 1085, 1, 0, 0, 0, 241, 1089, 1, 0, 0, 0, 243, 1093, 1, 0, 0, 0, 245, 1098, 1, 0, 0, 0, 247, 1102, 1, 0, 0, 0, 249, 1106, 1, 0, 0, 0, 251, 1110, 1, 0, 0, 0, 253, 1115, 1, 0, 0, 0, 255, 1120, 1, 0, 0, 0, 257, 1123, 1, 0, 0, 0, 259, 1127, 1, 0, 0, 0, 261, 1131, 1, 0, 0, 0, 263, 1135, 1, 0, 0, 0, 265, 1139, 1, 0, 0, 0, 267, 1144, 1, 0, 0, 0, 269, 1149, 1, 0, 0, 0, 271, 1154, 1, 0, 0, 0, 273, 1161, 1, 0, 0, 0, 275, 1170, 1, 0, 0, 0, 277, 1177, 1, 0, 0, 0, 279, 1181, 1, 0, 0, 0, 281, 1185, 1, 0, 0, 0, 283, 1189, 1, 0, 0, 0, 285, 1193, 1, 0, 0, 0, 287, 1199, 1, 0, 0, 0, 289, 1203, 1, 0, 0, 0, 291, 1207, 1, 0, 0, 0, 293, 1211, 1, 0, 0, 0, 295, 1215, 1, 0, 0, 0, 297, 1219, 1, 0, 0, 0, 299, 1223, 1, 0, 0, 0, 301, 1228, 1, 0, 0, 0, 303, 1233, 1, 0, 0, 0, 305, 1237, 1, 0, 0, 0, 307, 1241, 1, 0, 0, 0, 309, 1245, 1, 0, 0, 0, 311, 1250, 1, 0, 0, 0, 313, 1254, 1, 0, 0, 0, 315, 1259, 1, 0, 0, 0, 317, 1264, 1, 0, 0, 0, 319, 1268, 1, 0, 0, 0, 321, 1272, 1, 0, 0, 0, 323, 1276, 1, 0, 0, 0, 325, 1280, 1, 0, 0, 0, 327, 1284, 1, 0, 0, 0, 329, 1289, 1, 0, 0, 0, 331, 1294, 1, 0, 0, 0, 333, 1298, 1, 0, 0, 0, 335, 1302, 1, 0, 0, 0, 337, 1306, 1, 0, 0, 0, 339, 1311, 1, 0, 0, 0, 341, 1320, 1, 0, 0, 0, 343, 1324, 1, 0, 0, 0, 345, 1328, 1, 0, 0, 0, 347, 1332, 1, 0, 0, 0, 349, 1336, 1, 0, 0, 0, 351, 1341, 1, 0, 0, 0, 353, 1345, 1, 0, 0, 0, 355, 1349, 1, 0, 0, 0, 357, 1353, 1, 0, 0, 0, 359, 1358, 1, 0, 0, 0, 361, 1362, 1, 0, 0, 0, 363, 1366, 1, 0, 0, 0, 365, 1370, 1, 0, 0, 0, 367, 1374, 1, 0, 0, 0, 369, 1378, 1, 0, 0, 0, 371, 1384, 1, 0, 0, 0, 373, 1388, 1, 0, 0, 0, 375, 1392, 1, 0, 0, 0, 377, 1396, 1, 0, 0, 0, 379, 1400, 1, 0, 0, 0, 381, 1404, 1, 0, 0, 0, 383, 1408, 1, 0, 0, 0, 385, 1413, 1, 0, 0, 0, 387, 1419, 1, 0, 0, 0, 389, 1425, 1, 0, 0, 0, 391, 1429, 1, 0, 0, 0, 393, 1433, 1, 0, 0, 0, 395, 1437, 1, 0, 0, 0, 397, 1443, 1, 0, 0, 0, 399, 1449, 1, 0, 0, 0, 401, 1453, 1, 0, 0, 0, 403, 1457, 1, 0, 0, 0, 405, 1461, 1, 0, 0, 0, 407, 1467, 1, 0, 0, 0, 409, 1473, 1, 0, 0, 0, 411, 1479, 1, 0, 0, 0, 413, 414, 7, 0, 0, 0, 414, 415, 7, 1, 0, 0, 415, 416, 7, 2, 0, 0, 416, 417, 7, 2, 0, 0, 417, 418, 7, 3, 0, 0, 418, 419, 7, 4, 0, 0, 419, 420, 7, 5, 0, 0, 420, 421, 1, 0, 0, 0, 421, 422, 6, 0, 0, 0, 422, 16, 1, 0, 0, 0, 423, 424, 7, 0, 0, 0, 424, 425, 7, 6, 0, 0, 425, 426, 7, 7, 0, 0, 426, 427, 7, 8, 0, 0, 427, 428, 1, 0, 0, 0, 428, 429, 6, 1, 1, 0, 429, 18, 1, 0, 0, 0, 430, 431, 7, 3, 0, 0, 431, 432, 7, 9, 0, 0, 432, 433, 7, 6, 0, 0, 433, 434, 7, 1, 0, 0, 434, 435, 7, 4, 0, 0, 435, 436, 7, 10, 0, 0, 436, 437, 1, 0, 0, 0, 437, 438, 6, 2, 2, 0, 438, 20, 1, 0, 0, 0, 439, 440, 7, 3, 0, 0, 440, 441, 7, 11, 0, 0, 441, 442, 7, 12, 0, 0, 442, 443, 7, 13, 0, 0, 443, 444, 1, 0, 0, 0, 444, 445, 6, 3, 0, 0, 445, 22, 1, 0, 0, 0, 446, 447, 7, 3, 0, 0, 447, 448, 7, 14, 0, 0, 448, 449, 7, 8, 0, 0, 449, 450, 7, 13, 0, 0, 450, 451, 7, 12, 0, 0, 451, 452, 7, 1, 0, 0, 452, 453, 7, 9, 0, 0, 453, 454, 1, 0, 0, 0, 454, 455, 6, 4, 3, 0, 455, 24, 1, 0, 0, 0, 456, 457, 7, 15, 0, 0, 457, 458, 7, 6, 0, 0, 458, 459, 7, 7, 0, 0, 459, 460, 7, 16, 0, 0, 460, 461, 1, 0, 0, 0, 461, 462, 6, 5, 4, 0, 462, 26, 1, 0, 0, 0, 463, 464, 7, 17, 0, 0, 464, 465, 7, 6, 0, 0, 465, 466, 7, 7, 0, 0, 466, 467, 7, 18, 0, 0, 467, 468, 1, 0, 0, 0, 468, 469, 6, 6, 0, 0, 469, 28, 1, 0, 0, 0, 470, 471, 7, 18, 0, 0, 471, 472, 7, 3, 0, 0, 472, 473, 7, 3, 0, 0, 473, 474, 7, 8, 0, 0, 474, 475, 1, 0, 0, 0, 475, 476, 6, 7, 1, 0, 476, 30, 1, 0, 0, 0, 477, 478, 7, 13, 0, 0, 478, 479, 7, 1, 0, 0, 479, 480, 7, 16, 0, 0, 480, 481, 7, 1, 0, 0, 481, 482, 7, 5, 0, 0, 482, 483, 1, 0, 0, 0, 483, 484, 6, 8, 0, 0, 484, 32, 1, 0, 0, 0, 485, 486, 7, 16, 0, 0, 486, 487, 7, 11, 0, 0, 487, 488, 5, 95, 0, 0, 488, 489, 7, 3, 0, 0, 489, 490, 7, 14, 0, 0, 490, 491, 7, 8, 0, 0, 491, 492, 7, 12, 0, 0, 492, 493, 7, 9, 0, 0, 493, 494, 7, 0, 0, 0, 494, 495, 1, 0, 0, 0, 495, 496, 6, 9, 5, 0, 496, 34, 1, 0, 0, 0, 497, 498, 7, 6, 0, 0, 498, 499, 7, 3, 0, 0, 499, 500, 7, 9, 0, 0, 500, 501, 7, 12, 0, 0, 501, 502, 7, 16, 0, 0, 502, 503, 7, 3, 0, 0, 503, 504, 1, 0, 0, 0, 504, 505, 6, 10, 6, 0, 505, 36, 1, 0, 0, 0, 506, 507, 7, 6, 0, 0, 507, 508, 7, 7, 0, 0, 508, 509, 7, 19, 0, 0, 509, 510, 1, 0, 0, 0, 510, 511, 6, 11, 0, 0, 511, 38, 1, 0, 0, 0, 512, 513, 7, 2, 0, 0, 513, 514, 7, 10, 0, 0, 514, 515, 7, 7, 0, 0, 515, 516, 7, 19, 0, 0, 516, 517, 1, 0, 0, 0, 517, 518, 6, 12, 7, 0, 518, 40, 1, 0, 0, 0, 519, 520, 7, 2, 0, 0, 520, 521, 7, 7, 0, 0, 521, 522, 7, 6, 0, 0, 522, 523, 7, 5, 0, 0, 523, 524, 1, 0, 0, 0, 524, 525, 6, 13, 0, 0, 525, 42, 1, 0, 0, 0, 526, 527, 7, 2, 0, 0, 527, 528, 7, 5, 0, 0, 528, 529, 7, 12, 0, 0, 529, 530, 7, 5, 0, 0, 530, 531, 7, 2, 0, 0, 531, 532, 1, 0, 0, 0, 532, 533, 6, 14, 0, 0, 533, 44, 1, 0, 0, 0, 534, 535, 7, 19, 0, 0, 535, 536, 7, 10, 0, 0, 536, 537, 7, 3, 0, 0, 537, 538, 7, 6, 0, 0, 538, 539, 7, 3, 0, 0, 539, 540, 1, 0, 0, 0, 540, 541, 6, 15, 0, 0, 541, 46, 1, 0, 0, 0, 542, 543, 4, 16, 0, 0, 543, 544, 7, 1, 0, 0, 544, 545, 7, 9, 0, 0, 545, 546, 7, 13, 0, 0, 546, 547, 7, 1, 0, 0, 547, 548, 7, 9, 0, 0, 548, 549, 7, 3, 0, 0, 549, 550, 7, 2, 0, 0, 550, 551, 7, 5, 0, 0, 551, 552, 7, 12, 0, 0, 552, 553, 7, 5, 0, 0, 553, 554, 7, 2, 0, 0, 554, 555, 1, 0, 0, 0, 555, 556, 6, 16, 0, 0, 556, 48, 1, 0, 0, 0, 557, 558, 4, 17, 1, 0, 558, 559, 7, 13, 0, 0, 559, 560, 7, 7, 0, 0, 560, 561, 7, 7, 0, 0, 561, 562, 7, 18, 0, 0, 562, 563, 7, 20, 0, 0, 563, 564, 7, 8, 0, 0, 564, 565, 1, 0, 0, 0, 565, 566, 6, 17, 8, 0, 566, 50, 1, 0, 0, 0, 567, 568, 4, 18, 2, 0, 568, 569, 7, 16, 0, 0, 569, 570, 7, 3, 0, 0, 570, 571, 7, 5, 0, 0, 571, 572, 7, 6, 0, 0, 572, 573, 7, 1, 0, 0, 573, 574, 7, 4, 0, 0, 574, 575, 7, 2, 0, 0, 575, 576, 1, 0, 0, 0, 576, 577, 6, 18, 9, 0, 577, 52, 1, 0, 0, 0, 578, 580, 8, 21, 0, 0, 579, 578, 1, 0, 0, 0, 580, 581, 1, 0, 0, 0, 581, 579, 1, 0, 0, 0, 581, 582, 1, 0, 0, 0, 582, 583, 1, 0, 0, 0, 583, 584, 6, 19, 0, 0, 584, 54, 1, 0, 0, 0, 585, 586, 5, 47, 0, 0, 586, 587, 5, 47, 0, 0, 587, 591, 1, 0, 0, 0, 588, 590, 8, 22, 0, 0, 589, 588, 1, 0, 0, 0, 590, 593, 1, 0, 0, 0, 591, 589, 1, 0, 0, 0, 591, 592, 1, 0, 0, 0, 592, 595, 1, 0, 0, 0, 593, 591, 1, 0, 0, 0, 594, 596, 5, 13, 0, 0, 595, 594, 1, 0, 0, 0, 595, 596, 1, 0, 0, 0, 596, 598, 1, 0, 0, 0, 597, 599, 5, 10, 0, 0, 598, 597, 1, 0, 0, 0, 598, 599, 1, 0, 0, 0, 599, 600, 1, 0, 0, 0, 600, 601, 6, 20, 10, 0, 601, 56, 1, 0, 0, 0, 602, 603, 5, 47, 0, 0, 603, 604, 5, 42, 0, 0, 604, 609, 1, 0, 0, 0, 605, 608, 3, 57, 21, 0, 606, 608, 9, 0, 0, 0, 607, 605, 1, 0, 0, 0, 607, 606, 1, 0, 0, 0, 608, 611, 1, 0, 0, 0, 609, 610, 1, 0, 0, 0, 609, 607, 1, 0, 0, 0, 610, 612, 1, 0, 0, 0, 611, 609, 1, 0, 0, 0, 612, 613, 5, 42, 0, 0, 613, 614, 5, 47, 0, 0, 614, 615, 1, 0, 0, 0, 615, 616, 6, 21, 10, 0, 616, 58, 1, 0, 0, 0, 617, 619, 7, 23, 0, 0, 618, 617, 1, 0, 0, 0, 619, 620, 1, 0, 0, 0, 620, 618, 1, 0, 0, 0, 620, 621, 1, 0, 0, 0, 621, 622, 1, 0, 0, 0, 622, 623, 6, 22, 10, 0, 623, 60, 1, 0, 0, 0, 624, 625, 5, 58, 0, 0, 625, 62, 1, 0, 0, 0, 626, 627, 5, 124, 0, 0, 627, 628, 1, 0, 0, 0, 628, 629, 6, 24, 11, 0, 629, 64, 1, 0, 0, 0, 630, 631, 7, 24, 0, 0, 631, 66, 1, 0, 0, 0, 632, 633, 7, 25, 0, 0, 633, 68, 1, 0, 0, 0, 634, 635, 5, 92, 0, 0, 635, 636, 7, 26, 0, 0, 636, 70, 1, 0, 0, 0, 637, 638, 8, 27, 0, 0, 638, 72, 1, 0, 0, 0, 639, 641, 7, 3, 0, 0, 640, 642, 7, 28, 0, 0, 641, 640, 1, 0, 0, 0, 641, 642, 1, 0, 0, 0, 642, 644, 1, 0, 0, 0, 643, 645, 3, 65, 25, 0, 644, 643, 1, 0, 0, 0, 645, 646, 1, 0, 0, 0, 646, 644, 1, 0, 0, 0, 646, 647, 1, 0, 0, 0, 647, 74, 1, 0, 0, 0, 648, 649, 5, 64, 0, 0, 649, 76, 1, 0, 0, 0, 650, 651, 5, 96, 0, 0, 651, 78, 1, 0, 0, 0, 652, 656, 8, 29, 0, 0, 653, 654, 5, 96, 0, 0, 654, 656, 5, 96, 0, 0, 655, 652, 1, 0, 0, 0, 655, 653, 1, 0, 0, 0, 656, 80, 1, 0, 0, 0, 657, 658, 5, 95, 0, 0, 658, 82, 1, 0, 0, 0, 659, 663, 3, 67, 26, 0, 660, 663, 3, 65, 25, 0, 661, 663, 3, 81, 33, 0, 662, 659, 1, 0, 0, 0, 662, 660, 1, 0, 0, 0, 662, 661, 1, 0, 0, 0, 663, 84, 1, 0, 0, 0, 664, 669, 5, 34, 0, 0, 665, 668, 3, 69, 27, 0, 666, 668, 3, 71, 28, 0, 667, 665, 1, 0, 0, 0, 667, 666, 1, 0, 0, 0, 668, 671, 1, 0, 0, 0, 669, 667, 1, 0, 0, 0, 669, 670, 1, 0, 0, 0, 670, 672, 1, 0, 0, 0, 671, 669, 1, 0, 0, 0, 672, 694, 5, 34, 0, 0, 673, 674, 5, 34, 0, 0, 674, 675, 5, 34, 0, 0, 675, 676, 5, 34, 0, 0, 676, 680, 1, 0, 0, 0, 677, 679, 8, 22, 0, 0, 678, 677, 1, 0, 0, 0, 679, 682, 1, 0, 0, 0, 680, 681, 1, 0, 0, 0, 680, 678, 1, 0, 0, 0, 681, 683, 1, 0, 0, 0, 682, 680, 1, 0, 0, 0, 683, 684, 5, 34, 0, 0, 684, 685, 5, 34, 0, 0, 685, 686, 5, 34, 0, 0, 686, 688, 1, 0, 0, 0, 687, 689, 5, 34, 0, 0, 688, 687, 1, 0, 0, 0, 688, 689, 1, 0, 0, 0, 689, 691, 1, 0, 0, 0, 690, 692, 5, 34, 0, 0, 691, 690, 1, 0, 0, 0, 691, 692, 1, 0, 0, 0, 692, 694, 1, 0, 0, 0, 693, 664, 1, 0, 0, 0, 693, 673, 1, 0, 0, 0, 694, 86, 1, 0, 0, 0, 695, 697, 3, 65, 25, 0, 696, 695, 1, 0, 0, 0, 697, 698, 1, 0, 0, 0, 698, 696, 1, 0, 0, 0, 698, 699, 1, 0, 0, 0, 699, 88, 1, 0, 0, 0, 700, 702, 3, 65, 25, 0, 701, 700, 1, 0, 0, 0, 702, 703, 1, 0, 0, 0, 703, 701, 1, 0, 0, 0, 703, 704, 1, 0, 0, 0, 704, 705, 1, 0, 0, 0, 705, 709, 3, 105, 45, 0, 706, 708, 3, 65, 25, 0, 707, 706, 1, 0, 0, 0, 708, 711, 1, 0, 0, 0, 709, 707, 1, 0, 0, 0, 709, 710, 1, 0, 0, 0, 710, 743, 1, 0, 0, 0, 711, 709, 1, 0, 0, 0, 712, 714, 3, 105, 45, 0, 713, 715, 3, 65, 25, 0, 714, 713, 1, 0, 0, 0, 715, 716, 1, 0, 0, 0, 716, 714, 1, 0, 0, 0, 716, 717, 1, 0, 0, 0, 717, 743, 1, 0, 0, 0, 718, 720, 3, 65, 25, 0, 719, 718, 1, 0, 0, 0, 720, 721, 1, 0, 0, 0, 721, 719, 1, 0, 0, 0, 721, 722, 1, 0, 0, 0, 722, 730, 1, 0, 0, 0, 723, 727, 3, 105, 45, 0, 724, 726, 3, 65, 25, 0, 725, 724, 1, 0, 0, 0, 726, 729, 1, 0, 0, 0, 727, 725, 1, 0, 0, 0, 727, 728, 1, 0, 0, 0, 728, 731, 1, 0, 0, 0, 729, 727, 1, 0, 0, 0, 730, 723, 1, 0, 0, 0, 730, 731, 1, 0, 0, 0, 731, 732, 1, 0, 0, 0, 732, 733, 3, 73, 29, 0, 733, 743, 1, 0, 0, 0, 734, 736, 3, 105, 45, 0, 735, 737, 3, 65, 25, 0, 736, 735, 1, 0, 0, 0, 737, 738, 1, 0, 0, 0, 738, 736, 1, 0, 0, 0, 738, 739, 1, 0, 0, 0, 739, 740, 1, 0, 0, 0, 740, 741, 3, 73, 29, 0, 741, 743, 1, 0, 0, 0, 742, 701, 1, 0, 0, 0, 742, 712, 1, 0, 0, 0, 742, 719, 1, 0, 0, 0, 742, 734, 1, 0, 0, 0, 743, 90, 1, 0, 0, 0, 744, 745, 7, 30, 0, 0, 745, 746, 7, 31, 0, 0, 746, 92, 1, 0, 0, 0, 747, 748, 7, 12, 0, 0, 748, 749, 7, 9, 0, 0, 749, 750, 7, 0, 0, 0, 750, 94, 1, 0, 0, 0, 751, 752, 7, 12, 0, 0, 752, 753, 7, 2, 0, 0, 753, 754, 7, 4, 0, 0, 754, 96, 1, 0, 0, 0, 755, 756, 5, 61, 0, 0, 756, 98, 1, 0, 0, 0, 757, 758, 5, 58, 0, 0, 758, 759, 5, 58, 0, 0, 759, 100, 1, 0, 0, 0, 760, 761, 5, 44, 0, 0, 761, 102, 1, 0, 0, 0, 762, 763, 7, 0, 0, 0, 763, 764, 7, 3, 0, 0, 764, 765, 7, 2, 0, 0, 765, 766, 7, 4, 0, 0, 766, 104, 1, 0, 0, 0, 767, 768, 5, 46, 0, 0, 768, 106, 1, 0, 0, 0, 769, 770, 7, 15, 0, 0, 770, 771, 7, 12, 0, 0, 771, 772, 7, 13, 0, 0, 772, 773, 7, 2, 0, 0, 773, 774, 7, 3, 0, 0, 774, 108, 1, 0, 0, 0, 775, 776, 7, 15, 0, 0, 776, 777, 7, 1, 0, 0, 777, 778, 7, 6, 0, 0, 778, 779, 7, 2, 0, 0, 779, 780, 7, 5, 0, 0, 780, 110, 1, 0, 0, 0, 781, 782, 7, 1, 0, 0, 782, 783, 7, 9, 0, 0, 783, 112, 1, 0, 0, 0, 784, 785, 7, 1, 0, 0, 785, 786, 7, 2, 0, 0, 786, 114, 1, 0, 0, 0, 787, 788, 7, 13, 0, 0, 788, 789, 7, 12, 0, 0, 789, 790, 7, 2, 0, 0, 790, 791, 7, 5, 0, 0, 791, 116, 1, 0, 0, 0, 792, 793, 7, 13, 0, 0, 793, 794, 7, 1, 0, 0, 794, 795, 7, 18, 0, 0, 795, 796, 7, 3, 0, 0, 796, 118, 1, 0, 0, 0, 797, 798, 5, 40, 0, 0, 798, 120, 1, 0, 0, 0, 799, 800, 7, 9, 0, 0, 800, 801, 7, 7, 0, 0, 801, 802, 7, 5, 0, 0, 802, 122, 1, 0, 0, 0, 803, 804, 7, 9, 0, 0, 804, 805, 7, 20, 0, 0, 805, 806, 7, 13, 0, 0, 806, 807, 7, 13, 0, 0, 807, 124, 1, 0, 0, 0, 808, 809, 7, 9, 0, 0, 809, 810, 7, 20, 0, 0, 810, 811, 7, 13, 0, 0, 811, 812, 7, 13, 0, 0, 812, 813, 7, 2, 0, 0, 813, 126, 1, 0, 0, 0, 814, 815, 7, 7, 0, 0, 815, 816, 7, 6, 0, 0, 816, 128, 1, 0, 0, 0, 817, 818, 5, 63, 0, 0, 818, 130, 1, 0, 0, 0, 819, 820, 7, 6, 0, 0, 820, 821, 7, 13, 0, 0, 821, 822, 7, 1, 0, 0, 822, 823, 7, 18, 0, 0, 823, 824, 7, 3, 0, 0, 824, 132, 1, 0, 0, 0, 825, 826, 5, 41, 0, 0, 826, 134, 1, 0, 0, 0, 827, 828, 7, 5, 0, 0, 828, 829, 7, 6, 0, 0, 829, 830, 7, 20, 0, 0, 830, 831, 7, 3, 0, 0, 831, 136, 1, 0, 0, 0, 832, 833, 5, 61, 0, 0, 833, 834, 5, 61, 0, 0, 834, 138, 1, 0, 0, 0, 835, 836, 5, 61, 0, 0, 836, 837, 5, 126, 0, 0, 837, 140, 1, 0, 0, 0, 838, 839, 5, 33, 0, 0, 839, 840, 5, 61, 0, 0, 840, 142, 1, 0, 0, 0, 841, 842, 5, 60, 0, 0, 842, 144, 1, 0, 0, 0, 843, 844, 5, 60, 0, 0, 844, 845, 5, 61, 0, 0, 845, 146, 1, 0, 0, 0, 846, 847, 5, 62, 0, 0, 847, 148, 1, 0, 0, 0, 848, 849, 5, 62, 0, 0, 849, 850, 5, 61, 0, 0, 850, 150, 1, 0, 0, 0, 851, 852, 5, 43, 0, 0, 852, 152, 1, 0, 0, 0, 853, 854, 5, 45, 0, 0, 854, 154, 1, 0, 0, 0, 855, 856, 5, 42, 0, 0, 856, 156, 1, 0, 0, 0, 857, 858, 5, 47, 0, 0, 858, 158, 1, 0, 0, 0, 859, 860, 5, 37, 0, 0, 860, 160, 1, 0, 0, 0, 861, 862, 4, 73, 3, 0, 862, 863, 3, 61, 23, 0, 863, 864, 1, 0, 0, 0, 864, 865, 6, 73, 12, 0, 865, 162, 1, 0, 0, 0, 866, 867, 3, 45, 15, 0, 867, 868, 1, 0, 0, 0, 868, 869, 6, 74, 13, 0, 869, 164, 1, 0, 0, 0, 870, 873, 3, 129, 57, 0, 871, 874, 3, 67, 26, 0, 872, 874, 3, 81, 33, 0, 873, 871, 1, 0, 0, 0, 873, 872, 1, 0, 0, 0, 874, 878, 1, 0, 0, 0, 875, 877, 3, 83, 34, 0, 876, 875, 1, 0, 0, 0, 877, 880, 1, 0, 0, 0, 878, 876, 1, 0, 0, 0, 878, 879, 1, 0, 0, 0, 879, 888, 1, 0, 0, 0, 880, 878, 1, 0, 0, 0, 881, 883, 3, 129, 57, 0, 882, 884, 3, 65, 25, 0, 883, 882, 1, 0, 0, 0, 884, 885, 1, 0, 0, 0, 885, 883, 1, 0, 0, 0, 885, 886, 1, 0, 0, 0, 886, 888, 1, 0, 0, 0, 887, 870, 1, 0, 0, 0, 887, 881, 1, 0, 0, 0, 888, 166, 1, 0, 0, 0, 889, 890, 5, 91, 0, 0, 890, 891, 1, 0, 0, 0, 891, 892, 6, 76, 0, 0, 892, 893, 6, 76, 0, 0, 893, 168, 1, 0, 0, 0, 894, 895, 5, 93, 0, 0, 895, 896, 1, 0, 0, 0, 896, 897, 6, 77, 11, 0, 897, 898, 6, 77, 11, 0, 898, 170, 1, 0, 0, 0, 899, 903, 3, 67, 26, 0, 900, 902, 3, 83, 34, 0, 901, 900, 1, 0, 0, 0, 902, 905, 1, 0, 0, 0, 903, 901, 1, 0, 0, 0, 903, 904, 1, 0, 0, 0, 904, 916, 1, 0, 0, 0, 905, 903, 1, 0, 0, 0, 906, 909, 3, 81, 33, 0, 907, 909, 3, 75, 30, 0, 908, 906, 1, 0, 0, 0, 908, 907, 1, 0, 0, 0, 909, 911, 1, 0, 0, 0, 910, 912, 3, 83, 34, 0, 911, 910, 1, 0, 0, 0, 912, 913, 1, 0, 0, 0, 913, 911, 1, 0, 0, 0, 913, 914, 1, 0, 0, 0, 914, 916, 1, 0, 0, 0, 915, 899, 1, 0, 0, 0, 915, 908, 1, 0, 0, 0, 916, 172, 1, 0, 0, 0, 917, 919, 3, 77, 31, 0, 918, 920, 3, 79, 32, 0, 919, 918, 1, 0, 0, 0, 920, 921, 1, 0, 0, 0, 921, 919, 1, 0, 0, 0, 921, 922, 1, 0, 0, 0, 922, 923, 1, 0, 0, 0, 923, 924, 3, 77, 31, 0, 924, 174, 1, 0, 0, 0, 925, 926, 3, 173, 79, 0, 926, 176, 1, 0, 0, 0, 927, 928, 3, 55, 20, 0, 928, 929, 1, 0, 0, 0, 929, 930, 6, 81, 10, 0, 930, 178, 1, 0, 0, 0, 931, 932, 3, 57, 21, 0, 932, 933, 1, 0, 0, 0, 933, 934, 6, 82, 10, 0, 934, 180, 1, 0, 0, 0, 935, 936, 3, 59, 22, 0, 936, 937, 1, 0, 0, 0, 937, 938, 6, 83, 10, 0, 938, 182, 1, 0, 0, 0, 939, 940, 3, 167, 76, 0, 940, 941, 1, 0, 0, 0, 941, 942, 6, 84, 14, 0, 942, 943, 6, 84, 15, 0, 943, 184, 1, 0, 0, 0, 944, 945, 3, 63, 24, 0, 945, 946, 1, 0, 0, 0, 946, 947, 6, 85, 16, 0, 947, 948, 6, 85, 11, 0, 948, 186, 1, 0, 0, 0, 949, 950, 3, 59, 22, 0, 950, 951, 1, 0, 0, 0, 951, 952, 6, 86, 10, 0, 952, 188, 1, 0, 0, 0, 953, 954, 3, 55, 20, 0, 954, 955, 1, 0, 0, 0, 955, 956, 6, 87, 10, 0, 956, 190, 1, 0, 0, 0, 957, 958, 3, 57, 21, 0, 958, 959, 1, 0, 0, 0, 959, 960, 6, 88, 10, 0, 960, 192, 1, 0, 0, 0, 961, 962, 3, 63, 24, 0, 962, 963, 1, 0, 0, 0, 963, 964, 6, 89, 16, 0, 964, 965, 6, 89, 11, 0, 965, 194, 1, 0, 0, 0, 966, 967, 3, 167, 76, 0, 967, 968, 1, 0, 0, 0, 968, 969, 6, 90, 14, 0, 969, 196, 1, 0, 0, 0, 970, 971, 3, 169, 77, 0, 971, 972, 1, 0, 0, 0, 972, 973, 6, 91, 17, 0, 973, 198, 1, 0, 0, 0, 974, 975, 3, 61, 23, 0, 975, 976, 1, 0, 0, 0, 976, 977, 6, 92, 12, 0, 977, 200, 1, 0, 0, 0, 978, 979, 3, 101, 43, 0, 979, 980, 1, 0, 0, 0, 980, 981, 6, 93, 18, 0, 981, 202, 1, 0, 0, 0, 982, 983, 3, 97, 41, 0, 983, 984, 1, 0, 0, 0, 984, 985, 6, 94, 19, 0, 985, 204, 1, 0, 0, 0, 986, 987, 7, 16, 0, 0, 987, 988, 7, 3, 0, 0, 988, 989, 7, 5, 0, 0, 989, 990, 7, 12, 0, 0, 990, 991, 7, 0, 0, 0, 991, 992, 7, 12, 0, 0, 992, 993, 7, 5, 0, 0, 993, 994, 7, 12, 0, 0, 994, 206, 1, 0, 0, 0, 995, 999, 8, 32, 0, 0, 996, 997, 5, 47, 0, 0, 997, 999, 8, 33, 0, 0, 998, 995, 1, 0, 0, 0, 998, 996, 1, 0, 0, 0, 999, 208, 1, 0, 0, 0, 1000, 1002, 3, 207, 96, 0, 1001, 1000, 1, 0, 0, 0, 1002, 1003, 1, 0, 0, 0, 1003, 1001, 1, 0, 0, 0, 1003, 1004, 1, 0, 0, 0, 1004, 210, 1, 0, 0, 0, 1005, 1006, 3, 209, 97, 0, 1006, 1007, 1, 0, 0, 0, 1007, 1008, 6, 98, 20, 0, 1008, 212, 1, 0, 0, 0, 1009, 1010, 3, 85, 35, 0, 1010, 1011, 1, 0, 0, 0, 1011, 1012, 6, 99, 21, 0, 1012, 214, 1, 0, 0, 0, 1013, 1014, 3, 55, 20, 0, 1014, 1015, 1, 0, 0, 0, 1015, 1016, 6, 100, 10, 0, 1016, 216, 1, 0, 0, 0, 1017, 1018, 3, 57, 21, 0, 1018, 1019, 1, 0, 0, 0, 1019, 1020, 6, 101, 10, 0, 1020, 218, 1, 0, 0, 0, 1021, 1022, 3, 59, 22, 0, 1022, 1023, 1, 0, 0, 0, 1023, 1024, 6, 102, 10, 0, 1024, 220, 1, 0, 0, 0, 1025, 1026, 3, 63, 24, 0, 1026, 1027, 1, 0, 0, 0, 1027, 1028, 6, 103, 16, 0, 1028, 1029, 6, 103, 11, 0, 1029, 222, 1, 0, 0, 0, 1030, 1031, 3, 105, 45, 0, 1031, 1032, 1, 0, 0, 0, 1032, 1033, 6, 104, 22, 0, 1033, 224, 1, 0, 0, 0, 1034, 1035, 3, 101, 43, 0, 1035, 1036, 1, 0, 0, 0, 1036, 1037, 6, 105, 18, 0, 1037, 226, 1, 0, 0, 0, 1038, 1039, 4, 106, 4, 0, 1039, 1040, 3, 129, 57, 0, 1040, 1041, 1, 0, 0, 0, 1041, 1042, 6, 106, 23, 0, 1042, 228, 1, 0, 0, 0, 1043, 1044, 4, 107, 5, 0, 1044, 1045, 3, 165, 75, 0, 1045, 1046, 1, 0, 0, 0, 1046, 1047, 6, 107, 24, 0, 1047, 230, 1, 0, 0, 0, 1048, 1053, 3, 67, 26, 0, 1049, 1053, 3, 65, 25, 0, 1050, 1053, 3, 81, 33, 0, 1051, 1053, 3, 155, 70, 0, 1052, 1048, 1, 0, 0, 0, 1052, 1049, 1, 0, 0, 0, 1052, 1050, 1, 0, 0, 0, 1052, 1051, 1, 0, 0, 0, 1053, 232, 1, 0, 0, 0, 1054, 1057, 3, 67, 26, 0, 1055, 1057, 3, 155, 70, 0, 1056, 1054, 1, 0, 0, 0, 1056, 1055, 1, 0, 0, 0, 1057, 1061, 1, 0, 0, 0, 1058, 1060, 3, 231, 108, 0, 1059, 1058, 1, 0, 0, 0, 1060, 1063, 1, 0, 0, 0, 1061, 1059, 1, 0, 0, 0, 1061, 1062, 1, 0, 0, 0, 1062, 1074, 1, 0, 0, 0, 1063, 1061, 1, 0, 0, 0, 1064, 1067, 3, 81, 33, 0, 1065, 1067, 3, 75, 30, 0, 1066, 1064, 1, 0, 0, 0, 1066, 1065, 1, 0, 0, 0, 1067, 1069, 1, 0, 0, 0, 1068, 1070, 3, 231, 108, 0, 1069, 1068, 1, 0, 0, 0, 1070, 1071, 1, 0, 0, 0, 1071, 1069, 1, 0, 0, 0, 1071, 1072, 1, 0, 0, 0, 1072, 1074, 1, 0, 0, 0, 1073, 1056, 1, 0, 0, 0, 1073, 1066, 1, 0, 0, 0, 1074, 234, 1, 0, 0, 0, 1075, 1078, 3, 233, 109, 0, 1076, 1078, 3, 173, 79, 0, 1077, 1075, 1, 0, 0, 0, 1077, 1076, 1, 0, 0, 0, 1078, 1079, 1, 0, 0, 0, 1079, 1077, 1, 0, 0, 0, 1079, 1080, 1, 0, 0, 0, 1080, 236, 1, 0, 0, 0, 1081, 1082, 3, 55, 20, 0, 1082, 1083, 1, 0, 0, 0, 1083, 1084, 6, 111, 10, 0, 1084, 238, 1, 0, 0, 0, 1085, 1086, 3, 57, 21, 0, 1086, 1087, 1, 0, 0, 0, 1087, 1088, 6, 112, 10, 0, 1088, 240, 1, 0, 0, 0, 1089, 1090, 3, 59, 22, 0, 1090, 1091, 1, 0, 0, 0, 1091, 1092, 6, 113, 10, 0, 1092, 242, 1, 0, 0, 0, 1093, 1094, 3, 63, 24, 0, 1094, 1095, 1, 0, 0, 0, 1095, 1096, 6, 114, 16, 0, 1096, 1097, 6, 114, 11, 0, 1097, 244, 1, 0, 0, 0, 1098, 1099, 3, 97, 41, 0, 1099, 1100, 1, 0, 0, 0, 1100, 1101, 6, 115, 19, 0, 1101, 246, 1, 0, 0, 0, 1102, 1103, 3, 101, 43, 0, 1103, 1104, 1, 0, 0, 0, 1104, 1105, 6, 116, 18, 0, 1105, 248, 1, 0, 0, 0, 1106, 1107, 3, 105, 45, 0, 1107, 1108, 1, 0, 0, 0, 1108, 1109, 6, 117, 22, 0, 1109, 250, 1, 0, 0, 0, 1110, 1111, 4, 118, 6, 0, 1111, 1112, 3, 129, 57, 0, 1112, 1113, 1, 0, 0, 0, 1113, 1114, 6, 118, 23, 0, 1114, 252, 1, 0, 0, 0, 1115, 1116, 4, 119, 7, 0, 1116, 1117, 3, 165, 75, 0, 1117, 1118, 1, 0, 0, 0, 1118, 1119, 6, 119, 24, 0, 1119, 254, 1, 0, 0, 0, 1120, 1121, 7, 12, 0, 0, 1121, 1122, 7, 2, 0, 0, 1122, 256, 1, 0, 0, 0, 1123, 1124, 3, 235, 110, 0, 1124, 1125, 1, 0, 0, 0, 1125, 1126, 6, 121, 25, 0, 1126, 258, 1, 0, 0, 0, 1127, 1128, 3, 55, 20, 0, 1128, 1129, 1, 0, 0, 0, 1129, 1130, 6, 122, 10, 0, 1130, 260, 1, 0, 0, 0, 1131, 1132, 3, 57, 21, 0, 1132, 1133, 1, 0, 0, 0, 1133, 1134, 6, 123, 10, 0, 1134, 262, 1, 0, 0, 0, 1135, 1136, 3, 59, 22, 0, 1136, 1137, 1, 0, 0, 0, 1137, 1138, 6, 124, 10, 0, 1138, 264, 1, 0, 0, 0, 1139, 1140, 3, 63, 24, 0, 1140, 1141, 1, 0, 0, 0, 1141, 1142, 6, 125, 16, 0, 1142, 1143, 6, 125, 11, 0, 1143, 266, 1, 0, 0, 0, 1144, 1145, 3, 167, 76, 0, 1145, 1146, 1, 0, 0, 0, 1146, 1147, 6, 126, 14, 0, 1147, 1148, 6, 126, 26, 0, 1148, 268, 1, 0, 0, 0, 1149, 1150, 7, 7, 0, 0, 1150, 1151, 7, 9, 0, 0, 1151, 1152, 1, 0, 0, 0, 1152, 1153, 6, 127, 27, 0, 1153, 270, 1, 0, 0, 0, 1154, 1155, 7, 19, 0, 0, 1155, 1156, 7, 1, 0, 0, 1156, 1157, 7, 5, 0, 0, 1157, 1158, 7, 10, 0, 0, 1158, 1159, 1, 0, 0, 0, 1159, 1160, 6, 128, 27, 0, 1160, 272, 1, 0, 0, 0, 1161, 1162, 8, 34, 0, 0, 1162, 274, 1, 0, 0, 0, 1163, 1165, 3, 273, 129, 0, 1164, 1163, 1, 0, 0, 0, 1165, 1166, 1, 0, 0, 0, 1166, 1164, 1, 0, 0, 0, 1166, 1167, 1, 0, 0, 0, 1167, 1168, 1, 0, 0, 0, 1168, 1169, 3, 61, 23, 0, 1169, 1171, 1, 0, 0, 0, 1170, 1164, 1, 0, 0, 0, 1170, 1171, 1, 0, 0, 0, 1171, 1173, 1, 0, 0, 0, 1172, 1174, 3, 273, 129, 0, 1173, 1172, 1, 0, 0, 0, 1174, 1175, 1, 0, 0, 0, 1175, 1173, 1, 0, 0, 0, 1175, 1176, 1, 0, 0, 0, 1176, 276, 1, 0, 0, 0, 1177, 1178, 3, 275, 130, 0, 1178, 1179, 1, 0, 0, 0, 1179, 1180, 6, 131, 28, 0, 1180, 278, 1, 0, 0, 0, 1181, 1182, 3, 55, 20, 0, 1182, 1183, 1, 0, 0, 0, 1183, 1184, 6, 132, 10, 0, 1184, 280, 1, 0, 0, 0, 1185, 1186, 3, 57, 21, 0, 1186, 1187, 1, 0, 0, 0, 1187, 1188, 6, 133, 10, 0, 1188, 282, 1, 0, 0, 0, 1189, 1190, 3, 59, 22, 0, 1190, 1191, 1, 0, 0, 0, 1191, 1192, 6, 134, 10, 0, 1192, 284, 1, 0, 0, 0, 1193, 1194, 3, 63, 24, 0, 1194, 1195, 1, 0, 0, 0, 1195, 1196, 6, 135, 16, 0, 1196, 1197, 6, 135, 11, 0, 1197, 1198, 6, 135, 11, 0, 1198, 286, 1, 0, 0, 0, 1199, 1200, 3, 97, 41, 0, 1200, 1201, 1, 0, 0, 0, 1201, 1202, 6, 136, 19, 0, 1202, 288, 1, 0, 0, 0, 1203, 1204, 3, 101, 43, 0, 1204, 1205, 1, 0, 0, 0, 1205, 1206, 6, 137, 18, 0, 1206, 290, 1, 0, 0, 0, 1207, 1208, 3, 105, 45, 0, 1208, 1209, 1, 0, 0, 0, 1209, 1210, 6, 138, 22, 0, 1210, 292, 1, 0, 0, 0, 1211, 1212, 3, 271, 128, 0, 1212, 1213, 1, 0, 0, 0, 1213, 1214, 6, 139, 29, 0, 1214, 294, 1, 0, 0, 0, 1215, 1216, 3, 235, 110, 0, 1216, 1217, 1, 0, 0, 0, 1217, 1218, 6, 140, 25, 0, 1218, 296, 1, 0, 0, 0, 1219, 1220, 3, 175, 80, 0, 1220, 1221, 1, 0, 0, 0, 1221, 1222, 6, 141, 30, 0, 1222, 298, 1, 0, 0, 0, 1223, 1224, 4, 142, 8, 0, 1224, 1225, 3, 129, 57, 0, 1225, 1226, 1, 0, 0, 0, 1226, 1227, 6, 142, 23, 0, 1227, 300, 1, 0, 0, 0, 1228, 1229, 4, 143, 9, 0, 1229, 1230, 3, 165, 75, 0, 1230, 1231, 1, 0, 0, 0, 1231, 1232, 6, 143, 24, 0, 1232, 302, 1, 0, 0, 0, 1233, 1234, 3, 55, 20, 0, 1234, 1235, 1, 0, 0, 0, 1235, 1236, 6, 144, 10, 0, 1236, 304, 1, 0, 0, 0, 1237, 1238, 3, 57, 21, 0, 1238, 1239, 1, 0, 0, 0, 1239, 1240, 6, 145, 10, 0, 1240, 306, 1, 0, 0, 0, 1241, 1242, 3, 59, 22, 0, 1242, 1243, 1, 0, 0, 0, 1243, 1244, 6, 146, 10, 0, 1244, 308, 1, 0, 0, 0, 1245, 1246, 3, 63, 24, 0, 1246, 1247, 1, 0, 0, 0, 1247, 1248, 6, 147, 16, 0, 1248, 1249, 6, 147, 11, 0, 1249, 310, 1, 0, 0, 0, 1250, 1251, 3, 105, 45, 0, 1251, 1252, 1, 0, 0, 0, 1252, 1253, 6, 148, 22, 0, 1253, 312, 1, 0, 0, 0, 1254, 1255, 4, 149, 10, 0, 1255, 1256, 3, 129, 57, 0, 1256, 1257, 1, 0, 0, 0, 1257, 1258, 6, 149, 23, 0, 1258, 314, 1, 0, 0, 0, 1259, 1260, 4, 150, 11, 0, 1260, 1261, 3, 165, 75, 0, 1261, 1262, 1, 0, 0, 0, 1262, 1263, 6, 150, 24, 0, 1263, 316, 1, 0, 0, 0, 1264, 1265, 3, 175, 80, 0, 1265, 1266, 1, 0, 0, 0, 1266, 1267, 6, 151, 30, 0, 1267, 318, 1, 0, 0, 0, 1268, 1269, 3, 171, 78, 0, 1269, 1270, 1, 0, 0, 0, 1270, 1271, 6, 152, 31, 0, 1271, 320, 1, 0, 0, 0, 1272, 1273, 3, 55, 20, 0, 1273, 1274, 1, 0, 0, 0, 1274, 1275, 6, 153, 10, 0, 1275, 322, 1, 0, 0, 0, 1276, 1277, 3, 57, 21, 0, 1277, 1278, 1, 0, 0, 0, 1278, 1279, 6, 154, 10, 0, 1279, 324, 1, 0, 0, 0, 1280, 1281, 3, 59, 22, 0, 1281, 1282, 1, 0, 0, 0, 1282, 1283, 6, 155, 10, 0, 1283, 326, 1, 0, 0, 0, 1284, 1285, 3, 63, 24, 0, 1285, 1286, 1, 0, 0, 0, 1286, 1287, 6, 156, 16, 0, 1287, 1288, 6, 156, 11, 0, 1288, 328, 1, 0, 0, 0, 1289, 1290, 7, 1, 0, 0, 1290, 1291, 7, 9, 0, 0, 1291, 1292, 7, 15, 0, 0, 1292, 1293, 7, 7, 0, 0, 1293, 330, 1, 0, 0, 0, 1294, 1295, 3, 55, 20, 0, 1295, 1296, 1, 0, 0, 0, 1296, 1297, 6, 158, 10, 0, 1297, 332, 1, 0, 0, 0, 1298, 1299, 3, 57, 21, 0, 1299, 1300, 1, 0, 0, 0, 1300, 1301, 6, 159, 10, 0, 1301, 334, 1, 0, 0, 0, 1302, 1303, 3, 59, 22, 0, 1303, 1304, 1, 0, 0, 0, 1304, 1305, 6, 160, 10, 0, 1305, 336, 1, 0, 0, 0, 1306, 1307, 3, 169, 77, 0, 1307, 1308, 1, 0, 0, 0, 1308, 1309, 6, 161, 17, 0, 1309, 1310, 6, 161, 11, 0, 1310, 338, 1, 0, 0, 0, 1311, 1312, 3, 61, 23, 0, 1312, 1313, 1, 0, 0, 0, 1313, 1314, 6, 162, 12, 0, 1314, 340, 1, 0, 0, 0, 1315, 1321, 3, 75, 30, 0, 1316, 1321, 3, 65, 25, 0, 1317, 1321, 3, 105, 45, 0, 1318, 1321, 3, 67, 26, 0, 1319, 1321, 3, 81, 33, 0, 1320, 1315, 1, 0, 0, 0, 1320, 1316, 1, 0, 0, 0, 1320, 1317, 1, 0, 0, 0, 1320, 1318, 1, 0, 0, 0, 1320, 1319, 1, 0, 0, 0, 1321, 1322, 1, 0, 0, 0, 1322, 1320, 1, 0, 0, 0, 1322, 1323, 1, 0, 0, 0, 1323, 342, 1, 0, 0, 0, 1324, 1325, 3, 55, 20, 0, 1325, 1326, 1, 0, 0, 0, 1326, 1327, 6, 164, 10, 0, 1327, 344, 1, 0, 0, 0, 1328, 1329, 3, 57, 21, 0, 1329, 1330, 1, 0, 0, 0, 1330, 1331, 6, 165, 10, 0, 1331, 346, 1, 0, 0, 0, 1332, 1333, 3, 59, 22, 0, 1333, 1334, 1, 0, 0, 0, 1334, 1335, 6, 166, 10, 0, 1335, 348, 1, 0, 0, 0, 1336, 1337, 3, 63, 24, 0, 1337, 1338, 1, 0, 0, 0, 1338, 1339, 6, 167, 16, 0, 1339, 1340, 6, 167, 11, 0, 1340, 350, 1, 0, 0, 0, 1341, 1342, 3, 61, 23, 0, 1342, 1343, 1, 0, 0, 0, 1343, 1344, 6, 168, 12, 0, 1344, 352, 1, 0, 0, 0, 1345, 1346, 3, 101, 43, 0, 1346, 1347, 1, 0, 0, 0, 1347, 1348, 6, 169, 18, 0, 1348, 354, 1, 0, 0, 0, 1349, 1350, 3, 105, 45, 0, 1350, 1351, 1, 0, 0, 0, 1351, 1352, 6, 170, 22, 0, 1352, 356, 1, 0, 0, 0, 1353, 1354, 3, 269, 127, 0, 1354, 1355, 1, 0, 0, 0, 1355, 1356, 6, 171, 32, 0, 1356, 1357, 6, 171, 33, 0, 1357, 358, 1, 0, 0, 0, 1358, 1359, 3, 209, 97, 0, 1359, 1360, 1, 0, 0, 0, 1360, 1361, 6, 172, 20, 0, 1361, 360, 1, 0, 0, 0, 1362, 1363, 3, 85, 35, 0, 1363, 1364, 1, 0, 0, 0, 1364, 1365, 6, 173, 21, 0, 1365, 362, 1, 0, 0, 0, 1366, 1367, 3, 55, 20, 0, 1367, 1368, 1, 0, 0, 0, 1368, 1369, 6, 174, 10, 0, 1369, 364, 1, 0, 0, 0, 1370, 1371, 3, 57, 21, 0, 1371, 1372, 1, 0, 0, 0, 1372, 1373, 6, 175, 10, 0, 1373, 366, 1, 0, 0, 0, 1374, 1375, 3, 59, 22, 0, 1375, 1376, 1, 0, 0, 0, 1376, 1377, 6, 176, 10, 0, 1377, 368, 1, 0, 0, 0, 1378, 1379, 3, 63, 24, 0, 1379, 1380, 1, 0, 0, 0, 1380, 1381, 6, 177, 16, 0, 1381, 1382, 6, 177, 11, 0, 1382, 1383, 6, 177, 11, 0, 1383, 370, 1, 0, 0, 0, 1384, 1385, 3, 101, 43, 0, 1385, 1386, 1, 0, 0, 0, 1386, 1387, 6, 178, 18, 0, 1387, 372, 1, 0, 0, 0, 1388, 1389, 3, 105, 45, 0, 1389, 1390, 1, 0, 0, 0, 1390, 1391, 6, 179, 22, 0, 1391, 374, 1, 0, 0, 0, 1392, 1393, 3, 235, 110, 0, 1393, 1394, 1, 0, 0, 0, 1394, 1395, 6, 180, 25, 0, 1395, 376, 1, 0, 0, 0, 1396, 1397, 3, 55, 20, 0, 1397, 1398, 1, 0, 0, 0, 1398, 1399, 6, 181, 10, 0, 1399, 378, 1, 0, 0, 0, 1400, 1401, 3, 57, 21, 0, 1401, 1402, 1, 0, 0, 0, 1402, 1403, 6, 182, 10, 0, 1403, 380, 1, 0, 0, 0, 1404, 1405, 3, 59, 22, 0, 1405, 1406, 1, 0, 0, 0, 1406, 1407, 6, 183, 10, 0, 1407, 382, 1, 0, 0, 0, 1408, 1409, 3, 63, 24, 0, 1409, 1410, 1, 0, 0, 0, 1410, 1411, 6, 184, 16, 0, 1411, 1412, 6, 184, 11, 0, 1412, 384, 1, 0, 0, 0, 1413, 1414, 3, 209, 97, 0, 1414, 1415, 1, 0, 0, 0, 1415, 1416, 6, 185, 20, 0, 1416, 1417, 6, 185, 11, 0, 1417, 1418, 6, 185, 34, 0, 1418, 386, 1, 0, 0, 0, 1419, 1420, 3, 85, 35, 0, 1420, 1421, 1, 0, 0, 0, 1421, 1422, 6, 186, 21, 0, 1422, 1423, 6, 186, 11, 0, 1423, 1424, 6, 186, 34, 0, 1424, 388, 1, 0, 0, 0, 1425, 1426, 3, 55, 20, 0, 1426, 1427, 1, 0, 0, 0, 1427, 1428, 6, 187, 10, 0, 1428, 390, 1, 0, 0, 0, 1429, 1430, 3, 57, 21, 0, 1430, 1431, 1, 0, 0, 0, 1431, 1432, 6, 188, 10, 0, 1432, 392, 1, 0, 0, 0, 1433, 1434, 3, 59, 22, 0, 1434, 1435, 1, 0, 0, 0, 1435, 1436, 6, 189, 10, 0, 1436, 394, 1, 0, 0, 0, 1437, 1438, 3, 61, 23, 0, 1438, 1439, 1, 0, 0, 0, 1439, 1440, 6, 190, 12, 0, 1440, 1441, 6, 190, 11, 0, 1441, 1442, 6, 190, 9, 0, 1442, 396, 1, 0, 0, 0, 1443, 1444, 3, 101, 43, 0, 1444, 1445, 1, 0, 0, 0, 1445, 1446, 6, 191, 18, 0, 1446, 1447, 6, 191, 11, 0, 1447, 1448, 6, 191, 9, 0, 1448, 398, 1, 0, 0, 0, 1449, 1450, 3, 55, 20, 0, 1450, 1451, 1, 0, 0, 0, 1451, 1452, 6, 192, 10, 0, 1452, 400, 1, 0, 0, 0, 1453, 1454, 3, 57, 21, 0, 1454, 1455, 1, 0, 0, 0, 1455, 1456, 6, 193, 10, 0, 1456, 402, 1, 0, 0, 0, 1457, 1458, 3, 59, 22, 0, 1458, 1459, 1, 0, 0, 0, 1459, 1460, 6, 194, 10, 0, 1460, 404, 1, 0, 0, 0, 1461, 1462, 3, 175, 80, 0, 1462, 1463, 1, 0, 0, 0, 1463, 1464, 6, 195, 11, 0, 1464, 1465, 6, 195, 0, 0, 1465, 1466, 6, 195, 30, 0, 1466, 406, 1, 0, 0, 0, 1467, 1468, 3, 171, 78, 0, 1468, 1469, 1, 0, 0, 0, 1469, 1470, 6, 196, 11, 0, 1470, 1471, 6, 196, 0, 0, 1471, 1472, 6, 196, 31, 0, 1472, 408, 1, 0, 0, 0, 1473, 1474, 3, 91, 38, 0, 1474, 1475, 1, 0, 0, 0, 1475, 1476, 6, 197, 11, 0, 1476, 1477, 6, 197, 0, 0, 1477, 1478, 6, 197, 35, 0, 1478, 410, 1, 0, 0, 0, 1479, 1480, 3, 63, 24, 0, 1480, 1481, 1, 0, 0, 0, 1481, 1482, 6, 198, 16, 0, 1482, 1483, 6, 198, 11, 0, 1483, 412, 1, 0, 0, 0, 65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 581, 591, 595, 598, 607, 609, 620, 641, 646, 655, 662, 667, 669, 680, 688, 691, 693, 698, 703, 709, 716, 721, 727, 730, 738, 742, 873, 878, 885, 887, 903, 908, 913, 915, 921, 998, 1003, 1052, 1056, 1061, 1066, 1071, 1073, 1077, 1079, 1166, 1170, 1175, 1320, 1322, 36, 5, 1, 0, 5, 4, 0, 5, 6, 0, 5, 2, 0, 5, 3, 0, 5, 8, 0, 5, 5, 0, 5, 9, 0, 5, 11, 0, 5, 13, 0, 0, 1, 0, 4, 0, 0, 7, 24, 0, 7, 16, 0, 7, 65, 0, 5, 0, 0, 7, 25, 0, 7, 66, 0, 7, 34, 0, 7, 32, 0, 7, 76, 0, 7, 26, 0, 7, 36, 0, 7, 48, 0, 7, 64, 0, 7, 80, 0, 5, 10, 0, 5, 7, 0, 7, 90, 0, 7, 89, 0, 7, 68, 0, 7, 67, 0, 7, 88, 0, 5, 12, 0, 5, 14, 0, 7, 29, 0] \ No newline at end of file diff --git a/packages/kbn-esql-ast/src/antlr/esql_lexer.tokens b/packages/kbn-esql-ast/src/antlr/esql_lexer.tokens index 4d1f42628914..3dd1a2c75403 100644 --- a/packages/kbn-esql-ast/src/antlr/esql_lexer.tokens +++ b/packages/kbn-esql-ast/src/antlr/esql_lexer.tokens @@ -21,46 +21,46 @@ UNKNOWN_CMD=20 LINE_COMMENT=21 MULTILINE_COMMENT=22 WS=23 -PIPE=24 -QUOTED_STRING=25 -INTEGER_LITERAL=26 -DECIMAL_LITERAL=27 -BY=28 -AND=29 -ASC=30 -ASSIGN=31 -CAST_OP=32 -COMMA=33 -DESC=34 -DOT=35 -FALSE=36 -FIRST=37 -IN=38 -IS=39 -LAST=40 -LIKE=41 -LP=42 -NOT=43 -NULL=44 -NULLS=45 -OR=46 -PARAM=47 -RLIKE=48 -RP=49 -TRUE=50 -EQ=51 -CIEQ=52 -NEQ=53 -LT=54 -LTE=55 -GT=56 -GTE=57 -PLUS=58 -MINUS=59 -ASTERISK=60 -SLASH=61 -PERCENT=62 -MATCH=63 +COLON=24 +PIPE=25 +QUOTED_STRING=26 +INTEGER_LITERAL=27 +DECIMAL_LITERAL=28 +BY=29 +AND=30 +ASC=31 +ASSIGN=32 +CAST_OP=33 +COMMA=34 +DESC=35 +DOT=36 +FALSE=37 +FIRST=38 +IN=39 +IS=40 +LAST=41 +LIKE=42 +LP=43 +NOT=44 +NULL=45 +NULLS=46 +OR=47 +PARAM=48 +RLIKE=49 +RP=50 +TRUE=51 +EQ=52 +CIEQ=53 +NEQ=54 +LT=55 +LTE=56 +GT=57 +GTE=58 +PLUS=59 +MINUS=60 +ASTERISK=61 +SLASH=62 +PERCENT=63 NAMED_OR_POSITIONAL_PARAM=64 OPENING_BRACKET=65 CLOSING_BRACKET=66 @@ -101,23 +101,22 @@ INFO=100 SHOW_LINE_COMMENT=101 SHOW_MULTILINE_COMMENT=102 SHOW_WS=103 -COLON=104 -SETTING=105 -SETTING_LINE_COMMENT=106 -SETTTING_MULTILINE_COMMENT=107 -SETTING_WS=108 -LOOKUP_LINE_COMMENT=109 -LOOKUP_MULTILINE_COMMENT=110 -LOOKUP_WS=111 -LOOKUP_FIELD_LINE_COMMENT=112 -LOOKUP_FIELD_MULTILINE_COMMENT=113 -LOOKUP_FIELD_WS=114 -METRICS_LINE_COMMENT=115 -METRICS_MULTILINE_COMMENT=116 -METRICS_WS=117 -CLOSING_METRICS_LINE_COMMENT=118 -CLOSING_METRICS_MULTILINE_COMMENT=119 -CLOSING_METRICS_WS=120 +SETTING=104 +SETTING_LINE_COMMENT=105 +SETTTING_MULTILINE_COMMENT=106 +SETTING_WS=107 +LOOKUP_LINE_COMMENT=108 +LOOKUP_MULTILINE_COMMENT=109 +LOOKUP_WS=110 +LOOKUP_FIELD_LINE_COMMENT=111 +LOOKUP_FIELD_MULTILINE_COMMENT=112 +LOOKUP_FIELD_WS=113 +METRICS_LINE_COMMENT=114 +METRICS_MULTILINE_COMMENT=115 +METRICS_WS=116 +CLOSING_METRICS_LINE_COMMENT=117 +CLOSING_METRICS_MULTILINE_COMMENT=118 +CLOSING_METRICS_WS=119 'dissect'=1 'drop'=2 'enrich'=3 @@ -134,47 +133,46 @@ CLOSING_METRICS_WS=120 'sort'=14 'stats'=15 'where'=16 -'|'=24 -'by'=28 -'and'=29 -'asc'=30 -'='=31 -'::'=32 -','=33 -'desc'=34 -'.'=35 -'false'=36 -'first'=37 -'in'=38 -'is'=39 -'last'=40 -'like'=41 -'('=42 -'not'=43 -'null'=44 -'nulls'=45 -'or'=46 -'?'=47 -'rlike'=48 -')'=49 -'true'=50 -'=='=51 -'=~'=52 -'!='=53 -'<'=54 -'<='=55 -'>'=56 -'>='=57 -'+'=58 -'-'=59 -'*'=60 -'/'=61 -'%'=62 -'match'=63 +':'=24 +'|'=25 +'by'=29 +'and'=30 +'asc'=31 +'='=32 +'::'=33 +','=34 +'desc'=35 +'.'=36 +'false'=37 +'first'=38 +'in'=39 +'is'=40 +'last'=41 +'like'=42 +'('=43 +'not'=44 +'null'=45 +'nulls'=46 +'or'=47 +'?'=48 +'rlike'=49 +')'=50 +'true'=51 +'=='=52 +'=~'=53 +'!='=54 +'<'=55 +'<='=56 +'>'=57 +'>='=58 +'+'=59 +'-'=60 +'*'=61 +'/'=62 +'%'=63 ']'=66 'metadata'=75 'as'=84 'on'=88 'with'=89 'info'=100 -':'=104 diff --git a/packages/kbn-esql-ast/src/antlr/esql_lexer.ts b/packages/kbn-esql-ast/src/antlr/esql_lexer.ts index 589148bf08c7..54546fef8590 100644 --- a/packages/kbn-esql-ast/src/antlr/esql_lexer.ts +++ b/packages/kbn-esql-ast/src/antlr/esql_lexer.ts @@ -46,46 +46,46 @@ export default class esql_lexer extends lexer_config { public static readonly LINE_COMMENT = 21; public static readonly MULTILINE_COMMENT = 22; public static readonly WS = 23; - public static readonly PIPE = 24; - public static readonly QUOTED_STRING = 25; - public static readonly INTEGER_LITERAL = 26; - public static readonly DECIMAL_LITERAL = 27; - public static readonly BY = 28; - public static readonly AND = 29; - public static readonly ASC = 30; - public static readonly ASSIGN = 31; - public static readonly CAST_OP = 32; - public static readonly COMMA = 33; - public static readonly DESC = 34; - public static readonly DOT = 35; - public static readonly FALSE = 36; - public static readonly FIRST = 37; - public static readonly IN = 38; - public static readonly IS = 39; - public static readonly LAST = 40; - public static readonly LIKE = 41; - public static readonly LP = 42; - public static readonly NOT = 43; - public static readonly NULL = 44; - public static readonly NULLS = 45; - public static readonly OR = 46; - public static readonly PARAM = 47; - public static readonly RLIKE = 48; - public static readonly RP = 49; - public static readonly TRUE = 50; - public static readonly EQ = 51; - public static readonly CIEQ = 52; - public static readonly NEQ = 53; - public static readonly LT = 54; - public static readonly LTE = 55; - public static readonly GT = 56; - public static readonly GTE = 57; - public static readonly PLUS = 58; - public static readonly MINUS = 59; - public static readonly ASTERISK = 60; - public static readonly SLASH = 61; - public static readonly PERCENT = 62; - public static readonly MATCH = 63; + public static readonly COLON = 24; + public static readonly PIPE = 25; + public static readonly QUOTED_STRING = 26; + public static readonly INTEGER_LITERAL = 27; + public static readonly DECIMAL_LITERAL = 28; + public static readonly BY = 29; + public static readonly AND = 30; + public static readonly ASC = 31; + public static readonly ASSIGN = 32; + public static readonly CAST_OP = 33; + public static readonly COMMA = 34; + public static readonly DESC = 35; + public static readonly DOT = 36; + public static readonly FALSE = 37; + public static readonly FIRST = 38; + public static readonly IN = 39; + public static readonly IS = 40; + public static readonly LAST = 41; + public static readonly LIKE = 42; + public static readonly LP = 43; + public static readonly NOT = 44; + public static readonly NULL = 45; + public static readonly NULLS = 46; + public static readonly OR = 47; + public static readonly PARAM = 48; + public static readonly RLIKE = 49; + public static readonly RP = 50; + public static readonly TRUE = 51; + public static readonly EQ = 52; + public static readonly CIEQ = 53; + public static readonly NEQ = 54; + public static readonly LT = 55; + public static readonly LTE = 56; + public static readonly GT = 57; + public static readonly GTE = 58; + public static readonly PLUS = 59; + public static readonly MINUS = 60; + public static readonly ASTERISK = 61; + public static readonly SLASH = 62; + public static readonly PERCENT = 63; public static readonly NAMED_OR_POSITIONAL_PARAM = 64; public static readonly OPENING_BRACKET = 65; public static readonly CLOSING_BRACKET = 66; @@ -126,23 +126,22 @@ export default class esql_lexer extends lexer_config { public static readonly SHOW_LINE_COMMENT = 101; public static readonly SHOW_MULTILINE_COMMENT = 102; public static readonly SHOW_WS = 103; - public static readonly COLON = 104; - public static readonly SETTING = 105; - public static readonly SETTING_LINE_COMMENT = 106; - public static readonly SETTTING_MULTILINE_COMMENT = 107; - public static readonly SETTING_WS = 108; - public static readonly LOOKUP_LINE_COMMENT = 109; - public static readonly LOOKUP_MULTILINE_COMMENT = 110; - public static readonly LOOKUP_WS = 111; - public static readonly LOOKUP_FIELD_LINE_COMMENT = 112; - public static readonly LOOKUP_FIELD_MULTILINE_COMMENT = 113; - public static readonly LOOKUP_FIELD_WS = 114; - public static readonly METRICS_LINE_COMMENT = 115; - public static readonly METRICS_MULTILINE_COMMENT = 116; - public static readonly METRICS_WS = 117; - public static readonly CLOSING_METRICS_LINE_COMMENT = 118; - public static readonly CLOSING_METRICS_MULTILINE_COMMENT = 119; - public static readonly CLOSING_METRICS_WS = 120; + public static readonly SETTING = 104; + public static readonly SETTING_LINE_COMMENT = 105; + public static readonly SETTTING_MULTILINE_COMMENT = 106; + public static readonly SETTING_WS = 107; + public static readonly LOOKUP_LINE_COMMENT = 108; + public static readonly LOOKUP_MULTILINE_COMMENT = 109; + public static readonly LOOKUP_WS = 110; + public static readonly LOOKUP_FIELD_LINE_COMMENT = 111; + public static readonly LOOKUP_FIELD_MULTILINE_COMMENT = 112; + public static readonly LOOKUP_FIELD_WS = 113; + public static readonly METRICS_LINE_COMMENT = 114; + public static readonly METRICS_MULTILINE_COMMENT = 115; + public static readonly METRICS_WS = 116; + public static readonly CLOSING_METRICS_LINE_COMMENT = 117; + public static readonly CLOSING_METRICS_MULTILINE_COMMENT = 118; + public static readonly CLOSING_METRICS_WS = 119; public static readonly EOF = Token.EOF; public static readonly EXPRESSION_MODE = 1; public static readonly EXPLAIN_MODE = 2; @@ -173,26 +172,26 @@ export default class esql_lexer extends lexer_config { null, null, null, null, null, null, - "'|'", null, + "':'", "'|'", null, null, - "'by'", "'and'", - "'asc'", "'='", - "'::'", "','", - "'desc'", "'.'", - "'false'", "'first'", - "'in'", "'is'", - "'last'", "'like'", - "'('", "'not'", - "'null'", "'nulls'", - "'or'", "'?'", - "'rlike'", "')'", - "'true'", "'=='", - "'=~'", "'!='", - "'<'", "'<='", - "'>'", "'>='", - "'+'", "'-'", - "'*'", "'/'", - "'%'", "'match'", + null, "'by'", + "'and'", "'asc'", + "'='", "'::'", + "','", "'desc'", + "'.'", "'false'", + "'first'", "'in'", + "'is'", "'last'", + "'like'", "'('", + "'not'", "'null'", + "'nulls'", "'or'", + "'?'", "'rlike'", + "')'", "'true'", + "'=='", "'=~'", + "'!='", "'<'", + "'<='", "'>'", + "'>='", "'+'", + "'-'", "'*'", + "'/'", "'%'", null, null, "']'", null, null, null, @@ -211,9 +210,7 @@ export default class esql_lexer extends lexer_config { null, null, null, null, null, null, - "'info'", null, - null, null, - "':'" ]; + "'info'" ]; public static readonly symbolicNames: (string | null)[] = [ null, "DISSECT", "DROP", "ENRICH", "EVAL", "EXPLAIN", @@ -229,8 +226,8 @@ export default class esql_lexer extends lexer_config { "UNKNOWN_CMD", "LINE_COMMENT", "MULTILINE_COMMENT", - "WS", "PIPE", - "QUOTED_STRING", + "WS", "COLON", + "PIPE", "QUOTED_STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "AND", @@ -251,7 +248,7 @@ export default class esql_lexer extends lexer_config { "GTE", "PLUS", "MINUS", "ASTERISK", "SLASH", "PERCENT", - "MATCH", "NAMED_OR_POSITIONAL_PARAM", + "NAMED_OR_POSITIONAL_PARAM", "OPENING_BRACKET", "CLOSING_BRACKET", "UNQUOTED_IDENTIFIER", @@ -288,7 +285,7 @@ export default class esql_lexer extends lexer_config { "INFO", "SHOW_LINE_COMMENT", "SHOW_MULTILINE_COMMENT", "SHOW_WS", - "COLON", "SETTING", + "SETTING", "SETTING_LINE_COMMENT", "SETTTING_MULTILINE_COMMENT", "SETTING_WS", @@ -317,13 +314,13 @@ export default class esql_lexer extends lexer_config { "DISSECT", "DROP", "ENRICH", "EVAL", "EXPLAIN", "FROM", "GROK", "KEEP", "LIMIT", "MV_EXPAND", "RENAME", "ROW", "SHOW", "SORT", "STATS", "WHERE", "DEV_INLINESTATS", "DEV_LOOKUP", "DEV_METRICS", "UNKNOWN_CMD", "LINE_COMMENT", - "MULTILINE_COMMENT", "WS", "PIPE", "DIGIT", "LETTER", "ESCAPE_SEQUENCE", + "MULTILINE_COMMENT", "WS", "COLON", "PIPE", "DIGIT", "LETTER", "ESCAPE_SEQUENCE", "UNESCAPED_CHARS", "EXPONENT", "ASPERAND", "BACKQUOTE", "BACKQUOTE_BLOCK", "UNDERSCORE", "UNQUOTED_ID_BODY", "QUOTED_STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "AND", "ASC", "ASSIGN", "CAST_OP", "COMMA", "DESC", "DOT", "FALSE", "FIRST", "IN", "IS", "LAST", "LIKE", "LP", "NOT", "NULL", "NULLS", "OR", "PARAM", "RLIKE", "RP", "TRUE", "EQ", "CIEQ", "NEQ", "LT", - "LTE", "GT", "GTE", "PLUS", "MINUS", "ASTERISK", "SLASH", "PERCENT", "MATCH", + "LTE", "GT", "GTE", "PLUS", "MINUS", "ASTERISK", "SLASH", "PERCENT", "EXPRESSION_COLON", "NESTED_WHERE", "NAMED_OR_POSITIONAL_PARAM", "OPENING_BRACKET", "CLOSING_BRACKET", "UNQUOTED_IDENTIFIER", "QUOTED_ID", "QUOTED_IDENTIFIER", "EXPR_LINE_COMMENT", "EXPR_MULTILINE_COMMENT", "EXPR_WS", "EXPLAIN_OPENING_BRACKET", "EXPLAIN_PIPE", @@ -346,7 +343,7 @@ export default class esql_lexer extends lexer_config { "MVEXPAND_DOT", "MVEXPAND_PARAM", "MVEXPAND_NAMED_OR_POSITIONAL_PARAM", "MVEXPAND_QUOTED_IDENTIFIER", "MVEXPAND_UNQUOTED_IDENTIFIER", "MVEXPAND_LINE_COMMENT", "MVEXPAND_MULTILINE_COMMENT", "MVEXPAND_WS", "SHOW_PIPE", "INFO", "SHOW_LINE_COMMENT", - "SHOW_MULTILINE_COMMENT", "SHOW_WS", "SETTING_CLOSING_BRACKET", "COLON", + "SHOW_MULTILINE_COMMENT", "SHOW_WS", "SETTING_CLOSING_BRACKET", "SETTING_COLON", "SETTING", "SETTING_LINE_COMMENT", "SETTTING_MULTILINE_COMMENT", "SETTING_WS", "LOOKUP_PIPE", "LOOKUP_COLON", "LOOKUP_COMMA", "LOOKUP_DOT", "LOOKUP_ON", "LOOKUP_UNQUOTED_SOURCE", "LOOKUP_QUOTED_SOURCE", "LOOKUP_LINE_COMMENT", @@ -386,21 +383,23 @@ export default class esql_lexer extends lexer_config { return this.DEV_LOOKUP_sempred(localctx, predIndex); case 18: return this.DEV_METRICS_sempred(localctx, predIndex); - case 105: - return this.PROJECT_PARAM_sempred(localctx, predIndex); + case 73: + return this.EXPRESSION_COLON_sempred(localctx, predIndex); case 106: + return this.PROJECT_PARAM_sempred(localctx, predIndex); + case 107: return this.PROJECT_NAMED_OR_POSITIONAL_PARAM_sempred(localctx, predIndex); - case 117: - return this.RENAME_PARAM_sempred(localctx, predIndex); case 118: + return this.RENAME_PARAM_sempred(localctx, predIndex); + case 119: return this.RENAME_NAMED_OR_POSITIONAL_PARAM_sempred(localctx, predIndex); - case 141: - return this.ENRICH_FIELD_PARAM_sempred(localctx, predIndex); case 142: + return this.ENRICH_FIELD_PARAM_sempred(localctx, predIndex); + case 143: return this.ENRICH_FIELD_NAMED_OR_POSITIONAL_PARAM_sempred(localctx, predIndex); - case 148: - return this.MVEXPAND_PARAM_sempred(localctx, predIndex); case 149: + return this.MVEXPAND_PARAM_sempred(localctx, predIndex); + case 150: return this.MVEXPAND_NAMED_OR_POSITIONAL_PARAM_sempred(localctx, predIndex); } return true; @@ -426,64 +425,71 @@ export default class esql_lexer extends lexer_config { } return true; } - private PROJECT_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { + private EXPRESSION_COLON_sempred(localctx: RuleContext, predIndex: number): boolean { switch (predIndex) { case 3: return this.isDevVersion(); } return true; } - private PROJECT_NAMED_OR_POSITIONAL_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { + private PROJECT_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { switch (predIndex) { case 4: return this.isDevVersion(); } return true; } - private RENAME_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { + private PROJECT_NAMED_OR_POSITIONAL_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { switch (predIndex) { case 5: return this.isDevVersion(); } return true; } - private RENAME_NAMED_OR_POSITIONAL_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { + private RENAME_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { switch (predIndex) { case 6: return this.isDevVersion(); } return true; } - private ENRICH_FIELD_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { + private RENAME_NAMED_OR_POSITIONAL_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { switch (predIndex) { case 7: return this.isDevVersion(); } return true; } - private ENRICH_FIELD_NAMED_OR_POSITIONAL_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { + private ENRICH_FIELD_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { switch (predIndex) { case 8: return this.isDevVersion(); } return true; } - private MVEXPAND_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { + private ENRICH_FIELD_NAMED_OR_POSITIONAL_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { switch (predIndex) { case 9: return this.isDevVersion(); } return true; } - private MVEXPAND_NAMED_OR_POSITIONAL_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { + private MVEXPAND_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { switch (predIndex) { case 10: return this.isDevVersion(); } return true; } + private MVEXPAND_NAMED_OR_POSITIONAL_PARAM_sempred(localctx: RuleContext, predIndex: number): boolean { + switch (predIndex) { + case 11: + return this.isDevVersion(); + } + return true; + } - public static readonly _serializedATN: number[] = [4,0,120,1479,6,-1,6, + public static readonly _serializedATN: number[] = [4,0,119,1484,6,-1,6, -1,6,-1,6,-1,6,-1,6,-1,6,-1,6,-1,6,-1,6,-1,6,-1,6,-1,6,-1,6,-1,6,-1,2,0, 7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7,6,2,7,7,7,2,8,7,8,2,9, 7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,13,7,13,2,14,7,14,2,15,7,15,2,16,7, @@ -514,483 +520,485 @@ export default class esql_lexer extends lexer_config { 2,175,7,175,2,176,7,176,2,177,7,177,2,178,7,178,2,179,7,179,2,180,7,180, 2,181,7,181,2,182,7,182,2,183,7,183,2,184,7,184,2,185,7,185,2,186,7,186, 2,187,7,187,2,188,7,188,2,189,7,189,2,190,7,190,2,191,7,191,2,192,7,192, - 2,193,7,193,2,194,7,194,2,195,7,195,2,196,7,196,2,197,7,197,1,0,1,0,1,0, - 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,2,1,2,1,2, - 1,2,1,2,1,2,1,2,1,2,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,4,1,4,1,4,1,4,1,4,1,4, - 1,4,1,4,1,4,1,4,1,5,1,5,1,5,1,5,1,5,1,5,1,5,1,6,1,6,1,6,1,6,1,6,1,6,1,6, - 1,7,1,7,1,7,1,7,1,7,1,7,1,7,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,9,1,9,1,9, - 1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,10,1,10,1,10,1,10,1,10,1,10,1,10, - 1,10,1,10,1,11,1,11,1,11,1,11,1,11,1,11,1,12,1,12,1,12,1,12,1,12,1,12,1, - 12,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,14,1,14,1,14,1,14,1,14,1,14,1,14, - 1,14,1,15,1,15,1,15,1,15,1,15,1,15,1,15,1,15,1,16,1,16,1,16,1,16,1,16,1, - 16,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1,17,1,17,1,17,1,17,1,17, - 1,17,1,17,1,17,1,17,1,17,1,18,1,18,1,18,1,18,1,18,1,18,1,18,1,18,1,18,1, - 18,1,18,1,19,4,19,578,8,19,11,19,12,19,579,1,19,1,19,1,20,1,20,1,20,1,20, - 5,20,588,8,20,10,20,12,20,591,9,20,1,20,3,20,594,8,20,1,20,3,20,597,8,20, - 1,20,1,20,1,21,1,21,1,21,1,21,1,21,5,21,606,8,21,10,21,12,21,609,9,21,1, - 21,1,21,1,21,1,21,1,21,1,22,4,22,617,8,22,11,22,12,22,618,1,22,1,22,1,23, - 1,23,1,23,1,23,1,24,1,24,1,25,1,25,1,26,1,26,1,26,1,27,1,27,1,28,1,28,3, - 28,638,8,28,1,28,4,28,641,8,28,11,28,12,28,642,1,29,1,29,1,30,1,30,1,31, - 1,31,1,31,3,31,652,8,31,1,32,1,32,1,33,1,33,1,33,3,33,659,8,33,1,34,1,34, - 1,34,5,34,664,8,34,10,34,12,34,667,9,34,1,34,1,34,1,34,1,34,1,34,1,34,5, - 34,675,8,34,10,34,12,34,678,9,34,1,34,1,34,1,34,1,34,1,34,3,34,685,8,34, - 1,34,3,34,688,8,34,3,34,690,8,34,1,35,4,35,693,8,35,11,35,12,35,694,1,36, - 4,36,698,8,36,11,36,12,36,699,1,36,1,36,5,36,704,8,36,10,36,12,36,707,9, - 36,1,36,1,36,4,36,711,8,36,11,36,12,36,712,1,36,4,36,716,8,36,11,36,12, - 36,717,1,36,1,36,5,36,722,8,36,10,36,12,36,725,9,36,3,36,727,8,36,1,36, - 1,36,1,36,1,36,4,36,733,8,36,11,36,12,36,734,1,36,1,36,3,36,739,8,36,1, - 37,1,37,1,37,1,38,1,38,1,38,1,38,1,39,1,39,1,39,1,39,1,40,1,40,1,41,1,41, - 1,41,1,42,1,42,1,43,1,43,1,43,1,43,1,43,1,44,1,44,1,45,1,45,1,45,1,45,1, - 45,1,45,1,46,1,46,1,46,1,46,1,46,1,46,1,47,1,47,1,47,1,48,1,48,1,48,1,49, - 1,49,1,49,1,49,1,49,1,50,1,50,1,50,1,50,1,50,1,51,1,51,1,52,1,52,1,52,1, - 52,1,53,1,53,1,53,1,53,1,53,1,54,1,54,1,54,1,54,1,54,1,54,1,55,1,55,1,55, - 1,56,1,56,1,57,1,57,1,57,1,57,1,57,1,57,1,58,1,58,1,59,1,59,1,59,1,59,1, - 59,1,60,1,60,1,60,1,61,1,61,1,61,1,62,1,62,1,62,1,63,1,63,1,64,1,64,1,64, - 1,65,1,65,1,66,1,66,1,66,1,67,1,67,1,68,1,68,1,69,1,69,1,70,1,70,1,71,1, - 71,1,72,1,72,1,72,1,72,1,72,1,72,1,73,1,73,1,73,1,73,1,74,1,74,1,74,3,74, - 871,8,74,1,74,5,74,874,8,74,10,74,12,74,877,9,74,1,74,1,74,4,74,881,8,74, - 11,74,12,74,882,3,74,885,8,74,1,75,1,75,1,75,1,75,1,75,1,76,1,76,1,76,1, - 76,1,76,1,77,1,77,5,77,899,8,77,10,77,12,77,902,9,77,1,77,1,77,3,77,906, - 8,77,1,77,4,77,909,8,77,11,77,12,77,910,3,77,913,8,77,1,78,1,78,4,78,917, - 8,78,11,78,12,78,918,1,78,1,78,1,79,1,79,1,80,1,80,1,80,1,80,1,81,1,81, - 1,81,1,81,1,82,1,82,1,82,1,82,1,83,1,83,1,83,1,83,1,83,1,84,1,84,1,84,1, - 84,1,84,1,85,1,85,1,85,1,85,1,86,1,86,1,86,1,86,1,87,1,87,1,87,1,87,1,88, - 1,88,1,88,1,88,1,88,1,89,1,89,1,89,1,89,1,90,1,90,1,90,1,90,1,91,1,91,1, - 91,1,91,1,92,1,92,1,92,1,92,1,93,1,93,1,93,1,93,1,94,1,94,1,94,1,94,1,94, - 1,94,1,94,1,94,1,94,1,95,1,95,1,95,3,95,996,8,95,1,96,4,96,999,8,96,11, - 96,12,96,1000,1,97,1,97,1,97,1,97,1,98,1,98,1,98,1,98,1,99,1,99,1,99,1, - 99,1,100,1,100,1,100,1,100,1,101,1,101,1,101,1,101,1,102,1,102,1,102,1, - 102,1,102,1,103,1,103,1,103,1,103,1,104,1,104,1,104,1,104,1,105,1,105,1, - 105,1,105,1,105,1,106,1,106,1,106,1,106,1,106,1,107,1,107,1,107,1,107,3, - 107,1050,8,107,1,108,1,108,3,108,1054,8,108,1,108,5,108,1057,8,108,10,108, - 12,108,1060,9,108,1,108,1,108,3,108,1064,8,108,1,108,4,108,1067,8,108,11, - 108,12,108,1068,3,108,1071,8,108,1,109,1,109,4,109,1075,8,109,11,109,12, - 109,1076,1,110,1,110,1,110,1,110,1,111,1,111,1,111,1,111,1,112,1,112,1, - 112,1,112,1,113,1,113,1,113,1,113,1,113,1,114,1,114,1,114,1,114,1,115,1, - 115,1,115,1,115,1,116,1,116,1,116,1,116,1,117,1,117,1,117,1,117,1,117,1, - 118,1,118,1,118,1,118,1,118,1,119,1,119,1,119,1,120,1,120,1,120,1,120,1, - 121,1,121,1,121,1,121,1,122,1,122,1,122,1,122,1,123,1,123,1,123,1,123,1, - 124,1,124,1,124,1,124,1,124,1,125,1,125,1,125,1,125,1,125,1,126,1,126,1, - 126,1,126,1,126,1,127,1,127,1,127,1,127,1,127,1,127,1,127,1,128,1,128,1, - 129,4,129,1162,8,129,11,129,12,129,1163,1,129,1,129,3,129,1168,8,129,1, - 129,4,129,1171,8,129,11,129,12,129,1172,1,130,1,130,1,130,1,130,1,131,1, - 131,1,131,1,131,1,132,1,132,1,132,1,132,1,133,1,133,1,133,1,133,1,134,1, - 134,1,134,1,134,1,134,1,134,1,135,1,135,1,135,1,135,1,136,1,136,1,136,1, - 136,1,137,1,137,1,137,1,137,1,138,1,138,1,138,1,138,1,139,1,139,1,139,1, - 139,1,140,1,140,1,140,1,140,1,141,1,141,1,141,1,141,1,141,1,142,1,142,1, - 142,1,142,1,142,1,143,1,143,1,143,1,143,1,144,1,144,1,144,1,144,1,145,1, - 145,1,145,1,145,1,146,1,146,1,146,1,146,1,146,1,147,1,147,1,147,1,147,1, - 148,1,148,1,148,1,148,1,148,1,149,1,149,1,149,1,149,1,149,1,150,1,150,1, - 150,1,150,1,151,1,151,1,151,1,151,1,152,1,152,1,152,1,152,1,153,1,153,1, - 153,1,153,1,154,1,154,1,154,1,154,1,155,1,155,1,155,1,155,1,155,1,156,1, - 156,1,156,1,156,1,156,1,157,1,157,1,157,1,157,1,158,1,158,1,158,1,158,1, - 159,1,159,1,159,1,159,1,160,1,160,1,160,1,160,1,160,1,161,1,161,1,162,1, - 162,1,162,1,162,1,162,4,162,1316,8,162,11,162,12,162,1317,1,163,1,163,1, - 163,1,163,1,164,1,164,1,164,1,164,1,165,1,165,1,165,1,165,1,166,1,166,1, - 166,1,166,1,166,1,167,1,167,1,167,1,167,1,168,1,168,1,168,1,168,1,169,1, - 169,1,169,1,169,1,170,1,170,1,170,1,170,1,170,1,171,1,171,1,171,1,171,1, - 172,1,172,1,172,1,172,1,173,1,173,1,173,1,173,1,174,1,174,1,174,1,174,1, - 175,1,175,1,175,1,175,1,176,1,176,1,176,1,176,1,176,1,176,1,177,1,177,1, - 177,1,177,1,178,1,178,1,178,1,178,1,179,1,179,1,179,1,179,1,180,1,180,1, - 180,1,180,1,181,1,181,1,181,1,181,1,182,1,182,1,182,1,182,1,183,1,183,1, - 183,1,183,1,183,1,184,1,184,1,184,1,184,1,184,1,184,1,185,1,185,1,185,1, - 185,1,185,1,185,1,186,1,186,1,186,1,186,1,187,1,187,1,187,1,187,1,188,1, - 188,1,188,1,188,1,189,1,189,1,189,1,189,1,189,1,189,1,190,1,190,1,190,1, - 190,1,190,1,190,1,191,1,191,1,191,1,191,1,192,1,192,1,192,1,192,1,193,1, - 193,1,193,1,193,1,194,1,194,1,194,1,194,1,194,1,194,1,195,1,195,1,195,1, - 195,1,195,1,195,1,196,1,196,1,196,1,196,1,196,1,196,1,197,1,197,1,197,1, - 197,1,197,2,607,676,0,198,15,1,17,2,19,3,21,4,23,5,25,6,27,7,29,8,31,9, - 33,10,35,11,37,12,39,13,41,14,43,15,45,16,47,17,49,18,51,19,53,20,55,21, - 57,22,59,23,61,24,63,0,65,0,67,0,69,0,71,0,73,0,75,0,77,0,79,0,81,0,83, - 25,85,26,87,27,89,28,91,29,93,30,95,31,97,32,99,33,101,34,103,35,105,36, - 107,37,109,38,111,39,113,40,115,41,117,42,119,43,121,44,123,45,125,46,127, - 47,129,48,131,49,133,50,135,51,137,52,139,53,141,54,143,55,145,56,147,57, - 149,58,151,59,153,60,155,61,157,62,159,63,161,0,163,64,165,65,167,66,169, - 67,171,0,173,68,175,69,177,70,179,71,181,0,183,0,185,72,187,73,189,74,191, - 0,193,0,195,0,197,0,199,0,201,0,203,75,205,0,207,76,209,0,211,0,213,77, - 215,78,217,79,219,0,221,0,223,0,225,0,227,0,229,0,231,0,233,80,235,81,237, - 82,239,83,241,0,243,0,245,0,247,0,249,0,251,0,253,84,255,0,257,85,259,86, - 261,87,263,0,265,0,267,88,269,89,271,0,273,90,275,0,277,91,279,92,281,93, - 283,0,285,0,287,0,289,0,291,0,293,0,295,0,297,0,299,0,301,94,303,95,305, - 96,307,0,309,0,311,0,313,0,315,0,317,0,319,97,321,98,323,99,325,0,327,100, - 329,101,331,102,333,103,335,0,337,104,339,105,341,106,343,107,345,108,347, - 0,349,0,351,0,353,0,355,0,357,0,359,0,361,109,363,110,365,111,367,0,369, - 0,371,0,373,0,375,112,377,113,379,114,381,0,383,0,385,0,387,115,389,116, - 391,117,393,0,395,0,397,118,399,119,401,120,403,0,405,0,407,0,409,0,15, - 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,35,2,0,68,68,100,100,2,0,73,73,105,105, - 2,0,83,83,115,115,2,0,69,69,101,101,2,0,67,67,99,99,2,0,84,84,116,116,2, - 0,82,82,114,114,2,0,79,79,111,111,2,0,80,80,112,112,2,0,78,78,110,110,2, - 0,72,72,104,104,2,0,86,86,118,118,2,0,65,65,97,97,2,0,76,76,108,108,2,0, - 88,88,120,120,2,0,70,70,102,102,2,0,77,77,109,109,2,0,71,71,103,103,2,0, - 75,75,107,107,2,0,87,87,119,119,2,0,85,85,117,117,6,0,9,10,13,13,32,32, - 47,47,91,91,93,93,2,0,10,10,13,13,3,0,9,10,13,13,32,32,1,0,48,57,2,0,65, - 90,97,122,8,0,34,34,78,78,82,82,84,84,92,92,110,110,114,114,116,116,4,0, - 10,10,13,13,34,34,92,92,2,0,43,43,45,45,1,0,96,96,2,0,66,66,98,98,2,0,89, - 89,121,121,11,0,9,10,13,13,32,32,34,34,44,44,47,47,58,58,61,61,91,91,93, - 93,124,124,2,0,42,42,47,47,11,0,9,10,13,13,32,32,34,35,44,44,47,47,58,58, - 60,60,62,63,92,92,124,124,1507,0,15,1,0,0,0,0,17,1,0,0,0,0,19,1,0,0,0,0, - 21,1,0,0,0,0,23,1,0,0,0,0,25,1,0,0,0,0,27,1,0,0,0,0,29,1,0,0,0,0,31,1,0, - 0,0,0,33,1,0,0,0,0,35,1,0,0,0,0,37,1,0,0,0,0,39,1,0,0,0,0,41,1,0,0,0,0, - 43,1,0,0,0,0,45,1,0,0,0,0,47,1,0,0,0,0,49,1,0,0,0,0,51,1,0,0,0,0,53,1,0, - 0,0,0,55,1,0,0,0,0,57,1,0,0,0,0,59,1,0,0,0,1,61,1,0,0,0,1,83,1,0,0,0,1, - 85,1,0,0,0,1,87,1,0,0,0,1,89,1,0,0,0,1,91,1,0,0,0,1,93,1,0,0,0,1,95,1,0, - 0,0,1,97,1,0,0,0,1,99,1,0,0,0,1,101,1,0,0,0,1,103,1,0,0,0,1,105,1,0,0,0, - 1,107,1,0,0,0,1,109,1,0,0,0,1,111,1,0,0,0,1,113,1,0,0,0,1,115,1,0,0,0,1, - 117,1,0,0,0,1,119,1,0,0,0,1,121,1,0,0,0,1,123,1,0,0,0,1,125,1,0,0,0,1,127, - 1,0,0,0,1,129,1,0,0,0,1,131,1,0,0,0,1,133,1,0,0,0,1,135,1,0,0,0,1,137,1, - 0,0,0,1,139,1,0,0,0,1,141,1,0,0,0,1,143,1,0,0,0,1,145,1,0,0,0,1,147,1,0, - 0,0,1,149,1,0,0,0,1,151,1,0,0,0,1,153,1,0,0,0,1,155,1,0,0,0,1,157,1,0,0, - 0,1,159,1,0,0,0,1,161,1,0,0,0,1,163,1,0,0,0,1,165,1,0,0,0,1,167,1,0,0,0, - 1,169,1,0,0,0,1,173,1,0,0,0,1,175,1,0,0,0,1,177,1,0,0,0,1,179,1,0,0,0,2, - 181,1,0,0,0,2,183,1,0,0,0,2,185,1,0,0,0,2,187,1,0,0,0,2,189,1,0,0,0,3,191, - 1,0,0,0,3,193,1,0,0,0,3,195,1,0,0,0,3,197,1,0,0,0,3,199,1,0,0,0,3,201,1, - 0,0,0,3,203,1,0,0,0,3,207,1,0,0,0,3,209,1,0,0,0,3,211,1,0,0,0,3,213,1,0, - 0,0,3,215,1,0,0,0,3,217,1,0,0,0,4,219,1,0,0,0,4,221,1,0,0,0,4,223,1,0,0, - 0,4,225,1,0,0,0,4,227,1,0,0,0,4,233,1,0,0,0,4,235,1,0,0,0,4,237,1,0,0,0, - 4,239,1,0,0,0,5,241,1,0,0,0,5,243,1,0,0,0,5,245,1,0,0,0,5,247,1,0,0,0,5, - 249,1,0,0,0,5,251,1,0,0,0,5,253,1,0,0,0,5,255,1,0,0,0,5,257,1,0,0,0,5,259, - 1,0,0,0,5,261,1,0,0,0,6,263,1,0,0,0,6,265,1,0,0,0,6,267,1,0,0,0,6,269,1, - 0,0,0,6,273,1,0,0,0,6,275,1,0,0,0,6,277,1,0,0,0,6,279,1,0,0,0,6,281,1,0, - 0,0,7,283,1,0,0,0,7,285,1,0,0,0,7,287,1,0,0,0,7,289,1,0,0,0,7,291,1,0,0, - 0,7,293,1,0,0,0,7,295,1,0,0,0,7,297,1,0,0,0,7,299,1,0,0,0,7,301,1,0,0,0, - 7,303,1,0,0,0,7,305,1,0,0,0,8,307,1,0,0,0,8,309,1,0,0,0,8,311,1,0,0,0,8, - 313,1,0,0,0,8,315,1,0,0,0,8,317,1,0,0,0,8,319,1,0,0,0,8,321,1,0,0,0,8,323, - 1,0,0,0,9,325,1,0,0,0,9,327,1,0,0,0,9,329,1,0,0,0,9,331,1,0,0,0,9,333,1, - 0,0,0,10,335,1,0,0,0,10,337,1,0,0,0,10,339,1,0,0,0,10,341,1,0,0,0,10,343, - 1,0,0,0,10,345,1,0,0,0,11,347,1,0,0,0,11,349,1,0,0,0,11,351,1,0,0,0,11, - 353,1,0,0,0,11,355,1,0,0,0,11,357,1,0,0,0,11,359,1,0,0,0,11,361,1,0,0,0, - 11,363,1,0,0,0,11,365,1,0,0,0,12,367,1,0,0,0,12,369,1,0,0,0,12,371,1,0, - 0,0,12,373,1,0,0,0,12,375,1,0,0,0,12,377,1,0,0,0,12,379,1,0,0,0,13,381, - 1,0,0,0,13,383,1,0,0,0,13,385,1,0,0,0,13,387,1,0,0,0,13,389,1,0,0,0,13, - 391,1,0,0,0,14,393,1,0,0,0,14,395,1,0,0,0,14,397,1,0,0,0,14,399,1,0,0,0, - 14,401,1,0,0,0,14,403,1,0,0,0,14,405,1,0,0,0,14,407,1,0,0,0,14,409,1,0, - 0,0,15,411,1,0,0,0,17,421,1,0,0,0,19,428,1,0,0,0,21,437,1,0,0,0,23,444, - 1,0,0,0,25,454,1,0,0,0,27,461,1,0,0,0,29,468,1,0,0,0,31,475,1,0,0,0,33, - 483,1,0,0,0,35,495,1,0,0,0,37,504,1,0,0,0,39,510,1,0,0,0,41,517,1,0,0,0, - 43,524,1,0,0,0,45,532,1,0,0,0,47,540,1,0,0,0,49,555,1,0,0,0,51,565,1,0, - 0,0,53,577,1,0,0,0,55,583,1,0,0,0,57,600,1,0,0,0,59,616,1,0,0,0,61,622, - 1,0,0,0,63,626,1,0,0,0,65,628,1,0,0,0,67,630,1,0,0,0,69,633,1,0,0,0,71, - 635,1,0,0,0,73,644,1,0,0,0,75,646,1,0,0,0,77,651,1,0,0,0,79,653,1,0,0,0, - 81,658,1,0,0,0,83,689,1,0,0,0,85,692,1,0,0,0,87,738,1,0,0,0,89,740,1,0, - 0,0,91,743,1,0,0,0,93,747,1,0,0,0,95,751,1,0,0,0,97,753,1,0,0,0,99,756, - 1,0,0,0,101,758,1,0,0,0,103,763,1,0,0,0,105,765,1,0,0,0,107,771,1,0,0,0, - 109,777,1,0,0,0,111,780,1,0,0,0,113,783,1,0,0,0,115,788,1,0,0,0,117,793, - 1,0,0,0,119,795,1,0,0,0,121,799,1,0,0,0,123,804,1,0,0,0,125,810,1,0,0,0, - 127,813,1,0,0,0,129,815,1,0,0,0,131,821,1,0,0,0,133,823,1,0,0,0,135,828, - 1,0,0,0,137,831,1,0,0,0,139,834,1,0,0,0,141,837,1,0,0,0,143,839,1,0,0,0, - 145,842,1,0,0,0,147,844,1,0,0,0,149,847,1,0,0,0,151,849,1,0,0,0,153,851, - 1,0,0,0,155,853,1,0,0,0,157,855,1,0,0,0,159,857,1,0,0,0,161,863,1,0,0,0, - 163,884,1,0,0,0,165,886,1,0,0,0,167,891,1,0,0,0,169,912,1,0,0,0,171,914, - 1,0,0,0,173,922,1,0,0,0,175,924,1,0,0,0,177,928,1,0,0,0,179,932,1,0,0,0, - 181,936,1,0,0,0,183,941,1,0,0,0,185,946,1,0,0,0,187,950,1,0,0,0,189,954, - 1,0,0,0,191,958,1,0,0,0,193,963,1,0,0,0,195,967,1,0,0,0,197,971,1,0,0,0, - 199,975,1,0,0,0,201,979,1,0,0,0,203,983,1,0,0,0,205,995,1,0,0,0,207,998, - 1,0,0,0,209,1002,1,0,0,0,211,1006,1,0,0,0,213,1010,1,0,0,0,215,1014,1,0, - 0,0,217,1018,1,0,0,0,219,1022,1,0,0,0,221,1027,1,0,0,0,223,1031,1,0,0,0, - 225,1035,1,0,0,0,227,1040,1,0,0,0,229,1049,1,0,0,0,231,1070,1,0,0,0,233, - 1074,1,0,0,0,235,1078,1,0,0,0,237,1082,1,0,0,0,239,1086,1,0,0,0,241,1090, - 1,0,0,0,243,1095,1,0,0,0,245,1099,1,0,0,0,247,1103,1,0,0,0,249,1107,1,0, - 0,0,251,1112,1,0,0,0,253,1117,1,0,0,0,255,1120,1,0,0,0,257,1124,1,0,0,0, - 259,1128,1,0,0,0,261,1132,1,0,0,0,263,1136,1,0,0,0,265,1141,1,0,0,0,267, - 1146,1,0,0,0,269,1151,1,0,0,0,271,1158,1,0,0,0,273,1167,1,0,0,0,275,1174, - 1,0,0,0,277,1178,1,0,0,0,279,1182,1,0,0,0,281,1186,1,0,0,0,283,1190,1,0, - 0,0,285,1196,1,0,0,0,287,1200,1,0,0,0,289,1204,1,0,0,0,291,1208,1,0,0,0, - 293,1212,1,0,0,0,295,1216,1,0,0,0,297,1220,1,0,0,0,299,1225,1,0,0,0,301, - 1230,1,0,0,0,303,1234,1,0,0,0,305,1238,1,0,0,0,307,1242,1,0,0,0,309,1247, - 1,0,0,0,311,1251,1,0,0,0,313,1256,1,0,0,0,315,1261,1,0,0,0,317,1265,1,0, - 0,0,319,1269,1,0,0,0,321,1273,1,0,0,0,323,1277,1,0,0,0,325,1281,1,0,0,0, - 327,1286,1,0,0,0,329,1291,1,0,0,0,331,1295,1,0,0,0,333,1299,1,0,0,0,335, - 1303,1,0,0,0,337,1308,1,0,0,0,339,1315,1,0,0,0,341,1319,1,0,0,0,343,1323, - 1,0,0,0,345,1327,1,0,0,0,347,1331,1,0,0,0,349,1336,1,0,0,0,351,1340,1,0, - 0,0,353,1344,1,0,0,0,355,1348,1,0,0,0,357,1353,1,0,0,0,359,1357,1,0,0,0, - 361,1361,1,0,0,0,363,1365,1,0,0,0,365,1369,1,0,0,0,367,1373,1,0,0,0,369, - 1379,1,0,0,0,371,1383,1,0,0,0,373,1387,1,0,0,0,375,1391,1,0,0,0,377,1395, - 1,0,0,0,379,1399,1,0,0,0,381,1403,1,0,0,0,383,1408,1,0,0,0,385,1414,1,0, - 0,0,387,1420,1,0,0,0,389,1424,1,0,0,0,391,1428,1,0,0,0,393,1432,1,0,0,0, - 395,1438,1,0,0,0,397,1444,1,0,0,0,399,1448,1,0,0,0,401,1452,1,0,0,0,403, - 1456,1,0,0,0,405,1462,1,0,0,0,407,1468,1,0,0,0,409,1474,1,0,0,0,411,412, - 7,0,0,0,412,413,7,1,0,0,413,414,7,2,0,0,414,415,7,2,0,0,415,416,7,3,0,0, - 416,417,7,4,0,0,417,418,7,5,0,0,418,419,1,0,0,0,419,420,6,0,0,0,420,16, - 1,0,0,0,421,422,7,0,0,0,422,423,7,6,0,0,423,424,7,7,0,0,424,425,7,8,0,0, - 425,426,1,0,0,0,426,427,6,1,1,0,427,18,1,0,0,0,428,429,7,3,0,0,429,430, - 7,9,0,0,430,431,7,6,0,0,431,432,7,1,0,0,432,433,7,4,0,0,433,434,7,10,0, - 0,434,435,1,0,0,0,435,436,6,2,2,0,436,20,1,0,0,0,437,438,7,3,0,0,438,439, - 7,11,0,0,439,440,7,12,0,0,440,441,7,13,0,0,441,442,1,0,0,0,442,443,6,3, - 0,0,443,22,1,0,0,0,444,445,7,3,0,0,445,446,7,14,0,0,446,447,7,8,0,0,447, - 448,7,13,0,0,448,449,7,12,0,0,449,450,7,1,0,0,450,451,7,9,0,0,451,452,1, - 0,0,0,452,453,6,4,3,0,453,24,1,0,0,0,454,455,7,15,0,0,455,456,7,6,0,0,456, - 457,7,7,0,0,457,458,7,16,0,0,458,459,1,0,0,0,459,460,6,5,4,0,460,26,1,0, - 0,0,461,462,7,17,0,0,462,463,7,6,0,0,463,464,7,7,0,0,464,465,7,18,0,0,465, - 466,1,0,0,0,466,467,6,6,0,0,467,28,1,0,0,0,468,469,7,18,0,0,469,470,7,3, - 0,0,470,471,7,3,0,0,471,472,7,8,0,0,472,473,1,0,0,0,473,474,6,7,1,0,474, - 30,1,0,0,0,475,476,7,13,0,0,476,477,7,1,0,0,477,478,7,16,0,0,478,479,7, - 1,0,0,479,480,7,5,0,0,480,481,1,0,0,0,481,482,6,8,0,0,482,32,1,0,0,0,483, - 484,7,16,0,0,484,485,7,11,0,0,485,486,5,95,0,0,486,487,7,3,0,0,487,488, - 7,14,0,0,488,489,7,8,0,0,489,490,7,12,0,0,490,491,7,9,0,0,491,492,7,0,0, - 0,492,493,1,0,0,0,493,494,6,9,5,0,494,34,1,0,0,0,495,496,7,6,0,0,496,497, - 7,3,0,0,497,498,7,9,0,0,498,499,7,12,0,0,499,500,7,16,0,0,500,501,7,3,0, - 0,501,502,1,0,0,0,502,503,6,10,6,0,503,36,1,0,0,0,504,505,7,6,0,0,505,506, - 7,7,0,0,506,507,7,19,0,0,507,508,1,0,0,0,508,509,6,11,0,0,509,38,1,0,0, - 0,510,511,7,2,0,0,511,512,7,10,0,0,512,513,7,7,0,0,513,514,7,19,0,0,514, - 515,1,0,0,0,515,516,6,12,7,0,516,40,1,0,0,0,517,518,7,2,0,0,518,519,7,7, - 0,0,519,520,7,6,0,0,520,521,7,5,0,0,521,522,1,0,0,0,522,523,6,13,0,0,523, - 42,1,0,0,0,524,525,7,2,0,0,525,526,7,5,0,0,526,527,7,12,0,0,527,528,7,5, - 0,0,528,529,7,2,0,0,529,530,1,0,0,0,530,531,6,14,0,0,531,44,1,0,0,0,532, - 533,7,19,0,0,533,534,7,10,0,0,534,535,7,3,0,0,535,536,7,6,0,0,536,537,7, - 3,0,0,537,538,1,0,0,0,538,539,6,15,0,0,539,46,1,0,0,0,540,541,4,16,0,0, - 541,542,7,1,0,0,542,543,7,9,0,0,543,544,7,13,0,0,544,545,7,1,0,0,545,546, - 7,9,0,0,546,547,7,3,0,0,547,548,7,2,0,0,548,549,7,5,0,0,549,550,7,12,0, - 0,550,551,7,5,0,0,551,552,7,2,0,0,552,553,1,0,0,0,553,554,6,16,0,0,554, - 48,1,0,0,0,555,556,4,17,1,0,556,557,7,13,0,0,557,558,7,7,0,0,558,559,7, - 7,0,0,559,560,7,18,0,0,560,561,7,20,0,0,561,562,7,8,0,0,562,563,1,0,0,0, - 563,564,6,17,8,0,564,50,1,0,0,0,565,566,4,18,2,0,566,567,7,16,0,0,567,568, - 7,3,0,0,568,569,7,5,0,0,569,570,7,6,0,0,570,571,7,1,0,0,571,572,7,4,0,0, - 572,573,7,2,0,0,573,574,1,0,0,0,574,575,6,18,9,0,575,52,1,0,0,0,576,578, - 8,21,0,0,577,576,1,0,0,0,578,579,1,0,0,0,579,577,1,0,0,0,579,580,1,0,0, - 0,580,581,1,0,0,0,581,582,6,19,0,0,582,54,1,0,0,0,583,584,5,47,0,0,584, - 585,5,47,0,0,585,589,1,0,0,0,586,588,8,22,0,0,587,586,1,0,0,0,588,591,1, - 0,0,0,589,587,1,0,0,0,589,590,1,0,0,0,590,593,1,0,0,0,591,589,1,0,0,0,592, - 594,5,13,0,0,593,592,1,0,0,0,593,594,1,0,0,0,594,596,1,0,0,0,595,597,5, - 10,0,0,596,595,1,0,0,0,596,597,1,0,0,0,597,598,1,0,0,0,598,599,6,20,10, - 0,599,56,1,0,0,0,600,601,5,47,0,0,601,602,5,42,0,0,602,607,1,0,0,0,603, - 606,3,57,21,0,604,606,9,0,0,0,605,603,1,0,0,0,605,604,1,0,0,0,606,609,1, - 0,0,0,607,608,1,0,0,0,607,605,1,0,0,0,608,610,1,0,0,0,609,607,1,0,0,0,610, - 611,5,42,0,0,611,612,5,47,0,0,612,613,1,0,0,0,613,614,6,21,10,0,614,58, - 1,0,0,0,615,617,7,23,0,0,616,615,1,0,0,0,617,618,1,0,0,0,618,616,1,0,0, - 0,618,619,1,0,0,0,619,620,1,0,0,0,620,621,6,22,10,0,621,60,1,0,0,0,622, - 623,5,124,0,0,623,624,1,0,0,0,624,625,6,23,11,0,625,62,1,0,0,0,626,627, - 7,24,0,0,627,64,1,0,0,0,628,629,7,25,0,0,629,66,1,0,0,0,630,631,5,92,0, - 0,631,632,7,26,0,0,632,68,1,0,0,0,633,634,8,27,0,0,634,70,1,0,0,0,635,637, - 7,3,0,0,636,638,7,28,0,0,637,636,1,0,0,0,637,638,1,0,0,0,638,640,1,0,0, - 0,639,641,3,63,24,0,640,639,1,0,0,0,641,642,1,0,0,0,642,640,1,0,0,0,642, - 643,1,0,0,0,643,72,1,0,0,0,644,645,5,64,0,0,645,74,1,0,0,0,646,647,5,96, - 0,0,647,76,1,0,0,0,648,652,8,29,0,0,649,650,5,96,0,0,650,652,5,96,0,0,651, - 648,1,0,0,0,651,649,1,0,0,0,652,78,1,0,0,0,653,654,5,95,0,0,654,80,1,0, - 0,0,655,659,3,65,25,0,656,659,3,63,24,0,657,659,3,79,32,0,658,655,1,0,0, - 0,658,656,1,0,0,0,658,657,1,0,0,0,659,82,1,0,0,0,660,665,5,34,0,0,661,664, - 3,67,26,0,662,664,3,69,27,0,663,661,1,0,0,0,663,662,1,0,0,0,664,667,1,0, - 0,0,665,663,1,0,0,0,665,666,1,0,0,0,666,668,1,0,0,0,667,665,1,0,0,0,668, - 690,5,34,0,0,669,670,5,34,0,0,670,671,5,34,0,0,671,672,5,34,0,0,672,676, - 1,0,0,0,673,675,8,22,0,0,674,673,1,0,0,0,675,678,1,0,0,0,676,677,1,0,0, - 0,676,674,1,0,0,0,677,679,1,0,0,0,678,676,1,0,0,0,679,680,5,34,0,0,680, - 681,5,34,0,0,681,682,5,34,0,0,682,684,1,0,0,0,683,685,5,34,0,0,684,683, - 1,0,0,0,684,685,1,0,0,0,685,687,1,0,0,0,686,688,5,34,0,0,687,686,1,0,0, - 0,687,688,1,0,0,0,688,690,1,0,0,0,689,660,1,0,0,0,689,669,1,0,0,0,690,84, - 1,0,0,0,691,693,3,63,24,0,692,691,1,0,0,0,693,694,1,0,0,0,694,692,1,0,0, - 0,694,695,1,0,0,0,695,86,1,0,0,0,696,698,3,63,24,0,697,696,1,0,0,0,698, - 699,1,0,0,0,699,697,1,0,0,0,699,700,1,0,0,0,700,701,1,0,0,0,701,705,3,103, - 44,0,702,704,3,63,24,0,703,702,1,0,0,0,704,707,1,0,0,0,705,703,1,0,0,0, - 705,706,1,0,0,0,706,739,1,0,0,0,707,705,1,0,0,0,708,710,3,103,44,0,709, - 711,3,63,24,0,710,709,1,0,0,0,711,712,1,0,0,0,712,710,1,0,0,0,712,713,1, - 0,0,0,713,739,1,0,0,0,714,716,3,63,24,0,715,714,1,0,0,0,716,717,1,0,0,0, - 717,715,1,0,0,0,717,718,1,0,0,0,718,726,1,0,0,0,719,723,3,103,44,0,720, - 722,3,63,24,0,721,720,1,0,0,0,722,725,1,0,0,0,723,721,1,0,0,0,723,724,1, - 0,0,0,724,727,1,0,0,0,725,723,1,0,0,0,726,719,1,0,0,0,726,727,1,0,0,0,727, - 728,1,0,0,0,728,729,3,71,28,0,729,739,1,0,0,0,730,732,3,103,44,0,731,733, - 3,63,24,0,732,731,1,0,0,0,733,734,1,0,0,0,734,732,1,0,0,0,734,735,1,0,0, - 0,735,736,1,0,0,0,736,737,3,71,28,0,737,739,1,0,0,0,738,697,1,0,0,0,738, - 708,1,0,0,0,738,715,1,0,0,0,738,730,1,0,0,0,739,88,1,0,0,0,740,741,7,30, - 0,0,741,742,7,31,0,0,742,90,1,0,0,0,743,744,7,12,0,0,744,745,7,9,0,0,745, - 746,7,0,0,0,746,92,1,0,0,0,747,748,7,12,0,0,748,749,7,2,0,0,749,750,7,4, - 0,0,750,94,1,0,0,0,751,752,5,61,0,0,752,96,1,0,0,0,753,754,5,58,0,0,754, - 755,5,58,0,0,755,98,1,0,0,0,756,757,5,44,0,0,757,100,1,0,0,0,758,759,7, - 0,0,0,759,760,7,3,0,0,760,761,7,2,0,0,761,762,7,4,0,0,762,102,1,0,0,0,763, - 764,5,46,0,0,764,104,1,0,0,0,765,766,7,15,0,0,766,767,7,12,0,0,767,768, - 7,13,0,0,768,769,7,2,0,0,769,770,7,3,0,0,770,106,1,0,0,0,771,772,7,15,0, - 0,772,773,7,1,0,0,773,774,7,6,0,0,774,775,7,2,0,0,775,776,7,5,0,0,776,108, - 1,0,0,0,777,778,7,1,0,0,778,779,7,9,0,0,779,110,1,0,0,0,780,781,7,1,0,0, - 781,782,7,2,0,0,782,112,1,0,0,0,783,784,7,13,0,0,784,785,7,12,0,0,785,786, - 7,2,0,0,786,787,7,5,0,0,787,114,1,0,0,0,788,789,7,13,0,0,789,790,7,1,0, - 0,790,791,7,18,0,0,791,792,7,3,0,0,792,116,1,0,0,0,793,794,5,40,0,0,794, - 118,1,0,0,0,795,796,7,9,0,0,796,797,7,7,0,0,797,798,7,5,0,0,798,120,1,0, - 0,0,799,800,7,9,0,0,800,801,7,20,0,0,801,802,7,13,0,0,802,803,7,13,0,0, - 803,122,1,0,0,0,804,805,7,9,0,0,805,806,7,20,0,0,806,807,7,13,0,0,807,808, - 7,13,0,0,808,809,7,2,0,0,809,124,1,0,0,0,810,811,7,7,0,0,811,812,7,6,0, - 0,812,126,1,0,0,0,813,814,5,63,0,0,814,128,1,0,0,0,815,816,7,6,0,0,816, - 817,7,13,0,0,817,818,7,1,0,0,818,819,7,18,0,0,819,820,7,3,0,0,820,130,1, - 0,0,0,821,822,5,41,0,0,822,132,1,0,0,0,823,824,7,5,0,0,824,825,7,6,0,0, - 825,826,7,20,0,0,826,827,7,3,0,0,827,134,1,0,0,0,828,829,5,61,0,0,829,830, - 5,61,0,0,830,136,1,0,0,0,831,832,5,61,0,0,832,833,5,126,0,0,833,138,1,0, - 0,0,834,835,5,33,0,0,835,836,5,61,0,0,836,140,1,0,0,0,837,838,5,60,0,0, - 838,142,1,0,0,0,839,840,5,60,0,0,840,841,5,61,0,0,841,144,1,0,0,0,842,843, - 5,62,0,0,843,146,1,0,0,0,844,845,5,62,0,0,845,846,5,61,0,0,846,148,1,0, - 0,0,847,848,5,43,0,0,848,150,1,0,0,0,849,850,5,45,0,0,850,152,1,0,0,0,851, - 852,5,42,0,0,852,154,1,0,0,0,853,854,5,47,0,0,854,156,1,0,0,0,855,856,5, - 37,0,0,856,158,1,0,0,0,857,858,7,16,0,0,858,859,7,12,0,0,859,860,7,5,0, - 0,860,861,7,4,0,0,861,862,7,10,0,0,862,160,1,0,0,0,863,864,3,45,15,0,864, - 865,1,0,0,0,865,866,6,73,12,0,866,162,1,0,0,0,867,870,3,127,56,0,868,871, - 3,65,25,0,869,871,3,79,32,0,870,868,1,0,0,0,870,869,1,0,0,0,871,875,1,0, - 0,0,872,874,3,81,33,0,873,872,1,0,0,0,874,877,1,0,0,0,875,873,1,0,0,0,875, - 876,1,0,0,0,876,885,1,0,0,0,877,875,1,0,0,0,878,880,3,127,56,0,879,881, - 3,63,24,0,880,879,1,0,0,0,881,882,1,0,0,0,882,880,1,0,0,0,882,883,1,0,0, - 0,883,885,1,0,0,0,884,867,1,0,0,0,884,878,1,0,0,0,885,164,1,0,0,0,886,887, - 5,91,0,0,887,888,1,0,0,0,888,889,6,75,0,0,889,890,6,75,0,0,890,166,1,0, - 0,0,891,892,5,93,0,0,892,893,1,0,0,0,893,894,6,76,11,0,894,895,6,76,11, - 0,895,168,1,0,0,0,896,900,3,65,25,0,897,899,3,81,33,0,898,897,1,0,0,0,899, - 902,1,0,0,0,900,898,1,0,0,0,900,901,1,0,0,0,901,913,1,0,0,0,902,900,1,0, - 0,0,903,906,3,79,32,0,904,906,3,73,29,0,905,903,1,0,0,0,905,904,1,0,0,0, - 906,908,1,0,0,0,907,909,3,81,33,0,908,907,1,0,0,0,909,910,1,0,0,0,910,908, - 1,0,0,0,910,911,1,0,0,0,911,913,1,0,0,0,912,896,1,0,0,0,912,905,1,0,0,0, - 913,170,1,0,0,0,914,916,3,75,30,0,915,917,3,77,31,0,916,915,1,0,0,0,917, - 918,1,0,0,0,918,916,1,0,0,0,918,919,1,0,0,0,919,920,1,0,0,0,920,921,3,75, - 30,0,921,172,1,0,0,0,922,923,3,171,78,0,923,174,1,0,0,0,924,925,3,55,20, - 0,925,926,1,0,0,0,926,927,6,80,10,0,927,176,1,0,0,0,928,929,3,57,21,0,929, - 930,1,0,0,0,930,931,6,81,10,0,931,178,1,0,0,0,932,933,3,59,22,0,933,934, - 1,0,0,0,934,935,6,82,10,0,935,180,1,0,0,0,936,937,3,165,75,0,937,938,1, - 0,0,0,938,939,6,83,13,0,939,940,6,83,14,0,940,182,1,0,0,0,941,942,3,61, - 23,0,942,943,1,0,0,0,943,944,6,84,15,0,944,945,6,84,11,0,945,184,1,0,0, - 0,946,947,3,59,22,0,947,948,1,0,0,0,948,949,6,85,10,0,949,186,1,0,0,0,950, - 951,3,55,20,0,951,952,1,0,0,0,952,953,6,86,10,0,953,188,1,0,0,0,954,955, - 3,57,21,0,955,956,1,0,0,0,956,957,6,87,10,0,957,190,1,0,0,0,958,959,3,61, - 23,0,959,960,1,0,0,0,960,961,6,88,15,0,961,962,6,88,11,0,962,192,1,0,0, - 0,963,964,3,165,75,0,964,965,1,0,0,0,965,966,6,89,13,0,966,194,1,0,0,0, - 967,968,3,167,76,0,968,969,1,0,0,0,969,970,6,90,16,0,970,196,1,0,0,0,971, - 972,3,337,161,0,972,973,1,0,0,0,973,974,6,91,17,0,974,198,1,0,0,0,975,976, - 3,99,42,0,976,977,1,0,0,0,977,978,6,92,18,0,978,200,1,0,0,0,979,980,3,95, - 40,0,980,981,1,0,0,0,981,982,6,93,19,0,982,202,1,0,0,0,983,984,7,16,0,0, - 984,985,7,3,0,0,985,986,7,5,0,0,986,987,7,12,0,0,987,988,7,0,0,0,988,989, - 7,12,0,0,989,990,7,5,0,0,990,991,7,12,0,0,991,204,1,0,0,0,992,996,8,32, - 0,0,993,994,5,47,0,0,994,996,8,33,0,0,995,992,1,0,0,0,995,993,1,0,0,0,996, - 206,1,0,0,0,997,999,3,205,95,0,998,997,1,0,0,0,999,1000,1,0,0,0,1000,998, - 1,0,0,0,1000,1001,1,0,0,0,1001,208,1,0,0,0,1002,1003,3,207,96,0,1003,1004, - 1,0,0,0,1004,1005,6,97,20,0,1005,210,1,0,0,0,1006,1007,3,83,34,0,1007,1008, - 1,0,0,0,1008,1009,6,98,21,0,1009,212,1,0,0,0,1010,1011,3,55,20,0,1011,1012, - 1,0,0,0,1012,1013,6,99,10,0,1013,214,1,0,0,0,1014,1015,3,57,21,0,1015,1016, - 1,0,0,0,1016,1017,6,100,10,0,1017,216,1,0,0,0,1018,1019,3,59,22,0,1019, - 1020,1,0,0,0,1020,1021,6,101,10,0,1021,218,1,0,0,0,1022,1023,3,61,23,0, - 1023,1024,1,0,0,0,1024,1025,6,102,15,0,1025,1026,6,102,11,0,1026,220,1, - 0,0,0,1027,1028,3,103,44,0,1028,1029,1,0,0,0,1029,1030,6,103,22,0,1030, - 222,1,0,0,0,1031,1032,3,99,42,0,1032,1033,1,0,0,0,1033,1034,6,104,18,0, - 1034,224,1,0,0,0,1035,1036,4,105,3,0,1036,1037,3,127,56,0,1037,1038,1,0, - 0,0,1038,1039,6,105,23,0,1039,226,1,0,0,0,1040,1041,4,106,4,0,1041,1042, - 3,163,74,0,1042,1043,1,0,0,0,1043,1044,6,106,24,0,1044,228,1,0,0,0,1045, - 1050,3,65,25,0,1046,1050,3,63,24,0,1047,1050,3,79,32,0,1048,1050,3,153, - 69,0,1049,1045,1,0,0,0,1049,1046,1,0,0,0,1049,1047,1,0,0,0,1049,1048,1, - 0,0,0,1050,230,1,0,0,0,1051,1054,3,65,25,0,1052,1054,3,153,69,0,1053,1051, - 1,0,0,0,1053,1052,1,0,0,0,1054,1058,1,0,0,0,1055,1057,3,229,107,0,1056, - 1055,1,0,0,0,1057,1060,1,0,0,0,1058,1056,1,0,0,0,1058,1059,1,0,0,0,1059, - 1071,1,0,0,0,1060,1058,1,0,0,0,1061,1064,3,79,32,0,1062,1064,3,73,29,0, - 1063,1061,1,0,0,0,1063,1062,1,0,0,0,1064,1066,1,0,0,0,1065,1067,3,229,107, - 0,1066,1065,1,0,0,0,1067,1068,1,0,0,0,1068,1066,1,0,0,0,1068,1069,1,0,0, - 0,1069,1071,1,0,0,0,1070,1053,1,0,0,0,1070,1063,1,0,0,0,1071,232,1,0,0, - 0,1072,1075,3,231,108,0,1073,1075,3,171,78,0,1074,1072,1,0,0,0,1074,1073, - 1,0,0,0,1075,1076,1,0,0,0,1076,1074,1,0,0,0,1076,1077,1,0,0,0,1077,234, - 1,0,0,0,1078,1079,3,55,20,0,1079,1080,1,0,0,0,1080,1081,6,110,10,0,1081, - 236,1,0,0,0,1082,1083,3,57,21,0,1083,1084,1,0,0,0,1084,1085,6,111,10,0, - 1085,238,1,0,0,0,1086,1087,3,59,22,0,1087,1088,1,0,0,0,1088,1089,6,112, - 10,0,1089,240,1,0,0,0,1090,1091,3,61,23,0,1091,1092,1,0,0,0,1092,1093,6, - 113,15,0,1093,1094,6,113,11,0,1094,242,1,0,0,0,1095,1096,3,95,40,0,1096, - 1097,1,0,0,0,1097,1098,6,114,19,0,1098,244,1,0,0,0,1099,1100,3,99,42,0, - 1100,1101,1,0,0,0,1101,1102,6,115,18,0,1102,246,1,0,0,0,1103,1104,3,103, - 44,0,1104,1105,1,0,0,0,1105,1106,6,116,22,0,1106,248,1,0,0,0,1107,1108, - 4,117,5,0,1108,1109,3,127,56,0,1109,1110,1,0,0,0,1110,1111,6,117,23,0,1111, - 250,1,0,0,0,1112,1113,4,118,6,0,1113,1114,3,163,74,0,1114,1115,1,0,0,0, - 1115,1116,6,118,24,0,1116,252,1,0,0,0,1117,1118,7,12,0,0,1118,1119,7,2, - 0,0,1119,254,1,0,0,0,1120,1121,3,233,109,0,1121,1122,1,0,0,0,1122,1123, - 6,120,25,0,1123,256,1,0,0,0,1124,1125,3,55,20,0,1125,1126,1,0,0,0,1126, - 1127,6,121,10,0,1127,258,1,0,0,0,1128,1129,3,57,21,0,1129,1130,1,0,0,0, - 1130,1131,6,122,10,0,1131,260,1,0,0,0,1132,1133,3,59,22,0,1133,1134,1,0, - 0,0,1134,1135,6,123,10,0,1135,262,1,0,0,0,1136,1137,3,61,23,0,1137,1138, - 1,0,0,0,1138,1139,6,124,15,0,1139,1140,6,124,11,0,1140,264,1,0,0,0,1141, - 1142,3,165,75,0,1142,1143,1,0,0,0,1143,1144,6,125,13,0,1144,1145,6,125, - 26,0,1145,266,1,0,0,0,1146,1147,7,7,0,0,1147,1148,7,9,0,0,1148,1149,1,0, - 0,0,1149,1150,6,126,27,0,1150,268,1,0,0,0,1151,1152,7,19,0,0,1152,1153, - 7,1,0,0,1153,1154,7,5,0,0,1154,1155,7,10,0,0,1155,1156,1,0,0,0,1156,1157, - 6,127,27,0,1157,270,1,0,0,0,1158,1159,8,34,0,0,1159,272,1,0,0,0,1160,1162, - 3,271,128,0,1161,1160,1,0,0,0,1162,1163,1,0,0,0,1163,1161,1,0,0,0,1163, - 1164,1,0,0,0,1164,1165,1,0,0,0,1165,1166,3,337,161,0,1166,1168,1,0,0,0, - 1167,1161,1,0,0,0,1167,1168,1,0,0,0,1168,1170,1,0,0,0,1169,1171,3,271,128, - 0,1170,1169,1,0,0,0,1171,1172,1,0,0,0,1172,1170,1,0,0,0,1172,1173,1,0,0, - 0,1173,274,1,0,0,0,1174,1175,3,273,129,0,1175,1176,1,0,0,0,1176,1177,6, - 130,28,0,1177,276,1,0,0,0,1178,1179,3,55,20,0,1179,1180,1,0,0,0,1180,1181, - 6,131,10,0,1181,278,1,0,0,0,1182,1183,3,57,21,0,1183,1184,1,0,0,0,1184, - 1185,6,132,10,0,1185,280,1,0,0,0,1186,1187,3,59,22,0,1187,1188,1,0,0,0, - 1188,1189,6,133,10,0,1189,282,1,0,0,0,1190,1191,3,61,23,0,1191,1192,1,0, - 0,0,1192,1193,6,134,15,0,1193,1194,6,134,11,0,1194,1195,6,134,11,0,1195, - 284,1,0,0,0,1196,1197,3,95,40,0,1197,1198,1,0,0,0,1198,1199,6,135,19,0, - 1199,286,1,0,0,0,1200,1201,3,99,42,0,1201,1202,1,0,0,0,1202,1203,6,136, - 18,0,1203,288,1,0,0,0,1204,1205,3,103,44,0,1205,1206,1,0,0,0,1206,1207, - 6,137,22,0,1207,290,1,0,0,0,1208,1209,3,269,127,0,1209,1210,1,0,0,0,1210, - 1211,6,138,29,0,1211,292,1,0,0,0,1212,1213,3,233,109,0,1213,1214,1,0,0, - 0,1214,1215,6,139,25,0,1215,294,1,0,0,0,1216,1217,3,173,79,0,1217,1218, - 1,0,0,0,1218,1219,6,140,30,0,1219,296,1,0,0,0,1220,1221,4,141,7,0,1221, - 1222,3,127,56,0,1222,1223,1,0,0,0,1223,1224,6,141,23,0,1224,298,1,0,0,0, - 1225,1226,4,142,8,0,1226,1227,3,163,74,0,1227,1228,1,0,0,0,1228,1229,6, - 142,24,0,1229,300,1,0,0,0,1230,1231,3,55,20,0,1231,1232,1,0,0,0,1232,1233, - 6,143,10,0,1233,302,1,0,0,0,1234,1235,3,57,21,0,1235,1236,1,0,0,0,1236, - 1237,6,144,10,0,1237,304,1,0,0,0,1238,1239,3,59,22,0,1239,1240,1,0,0,0, - 1240,1241,6,145,10,0,1241,306,1,0,0,0,1242,1243,3,61,23,0,1243,1244,1,0, - 0,0,1244,1245,6,146,15,0,1245,1246,6,146,11,0,1246,308,1,0,0,0,1247,1248, - 3,103,44,0,1248,1249,1,0,0,0,1249,1250,6,147,22,0,1250,310,1,0,0,0,1251, - 1252,4,148,9,0,1252,1253,3,127,56,0,1253,1254,1,0,0,0,1254,1255,6,148,23, - 0,1255,312,1,0,0,0,1256,1257,4,149,10,0,1257,1258,3,163,74,0,1258,1259, - 1,0,0,0,1259,1260,6,149,24,0,1260,314,1,0,0,0,1261,1262,3,173,79,0,1262, - 1263,1,0,0,0,1263,1264,6,150,30,0,1264,316,1,0,0,0,1265,1266,3,169,77,0, - 1266,1267,1,0,0,0,1267,1268,6,151,31,0,1268,318,1,0,0,0,1269,1270,3,55, - 20,0,1270,1271,1,0,0,0,1271,1272,6,152,10,0,1272,320,1,0,0,0,1273,1274, - 3,57,21,0,1274,1275,1,0,0,0,1275,1276,6,153,10,0,1276,322,1,0,0,0,1277, - 1278,3,59,22,0,1278,1279,1,0,0,0,1279,1280,6,154,10,0,1280,324,1,0,0,0, - 1281,1282,3,61,23,0,1282,1283,1,0,0,0,1283,1284,6,155,15,0,1284,1285,6, - 155,11,0,1285,326,1,0,0,0,1286,1287,7,1,0,0,1287,1288,7,9,0,0,1288,1289, - 7,15,0,0,1289,1290,7,7,0,0,1290,328,1,0,0,0,1291,1292,3,55,20,0,1292,1293, - 1,0,0,0,1293,1294,6,157,10,0,1294,330,1,0,0,0,1295,1296,3,57,21,0,1296, - 1297,1,0,0,0,1297,1298,6,158,10,0,1298,332,1,0,0,0,1299,1300,3,59,22,0, - 1300,1301,1,0,0,0,1301,1302,6,159,10,0,1302,334,1,0,0,0,1303,1304,3,167, - 76,0,1304,1305,1,0,0,0,1305,1306,6,160,16,0,1306,1307,6,160,11,0,1307,336, - 1,0,0,0,1308,1309,5,58,0,0,1309,338,1,0,0,0,1310,1316,3,73,29,0,1311,1316, - 3,63,24,0,1312,1316,3,103,44,0,1313,1316,3,65,25,0,1314,1316,3,79,32,0, - 1315,1310,1,0,0,0,1315,1311,1,0,0,0,1315,1312,1,0,0,0,1315,1313,1,0,0,0, - 1315,1314,1,0,0,0,1316,1317,1,0,0,0,1317,1315,1,0,0,0,1317,1318,1,0,0,0, - 1318,340,1,0,0,0,1319,1320,3,55,20,0,1320,1321,1,0,0,0,1321,1322,6,163, - 10,0,1322,342,1,0,0,0,1323,1324,3,57,21,0,1324,1325,1,0,0,0,1325,1326,6, - 164,10,0,1326,344,1,0,0,0,1327,1328,3,59,22,0,1328,1329,1,0,0,0,1329,1330, - 6,165,10,0,1330,346,1,0,0,0,1331,1332,3,61,23,0,1332,1333,1,0,0,0,1333, - 1334,6,166,15,0,1334,1335,6,166,11,0,1335,348,1,0,0,0,1336,1337,3,337,161, - 0,1337,1338,1,0,0,0,1338,1339,6,167,17,0,1339,350,1,0,0,0,1340,1341,3,99, - 42,0,1341,1342,1,0,0,0,1342,1343,6,168,18,0,1343,352,1,0,0,0,1344,1345, - 3,103,44,0,1345,1346,1,0,0,0,1346,1347,6,169,22,0,1347,354,1,0,0,0,1348, - 1349,3,267,126,0,1349,1350,1,0,0,0,1350,1351,6,170,32,0,1351,1352,6,170, - 33,0,1352,356,1,0,0,0,1353,1354,3,207,96,0,1354,1355,1,0,0,0,1355,1356, - 6,171,20,0,1356,358,1,0,0,0,1357,1358,3,83,34,0,1358,1359,1,0,0,0,1359, - 1360,6,172,21,0,1360,360,1,0,0,0,1361,1362,3,55,20,0,1362,1363,1,0,0,0, - 1363,1364,6,173,10,0,1364,362,1,0,0,0,1365,1366,3,57,21,0,1366,1367,1,0, - 0,0,1367,1368,6,174,10,0,1368,364,1,0,0,0,1369,1370,3,59,22,0,1370,1371, - 1,0,0,0,1371,1372,6,175,10,0,1372,366,1,0,0,0,1373,1374,3,61,23,0,1374, - 1375,1,0,0,0,1375,1376,6,176,15,0,1376,1377,6,176,11,0,1377,1378,6,176, - 11,0,1378,368,1,0,0,0,1379,1380,3,99,42,0,1380,1381,1,0,0,0,1381,1382,6, - 177,18,0,1382,370,1,0,0,0,1383,1384,3,103,44,0,1384,1385,1,0,0,0,1385,1386, - 6,178,22,0,1386,372,1,0,0,0,1387,1388,3,233,109,0,1388,1389,1,0,0,0,1389, - 1390,6,179,25,0,1390,374,1,0,0,0,1391,1392,3,55,20,0,1392,1393,1,0,0,0, - 1393,1394,6,180,10,0,1394,376,1,0,0,0,1395,1396,3,57,21,0,1396,1397,1,0, - 0,0,1397,1398,6,181,10,0,1398,378,1,0,0,0,1399,1400,3,59,22,0,1400,1401, - 1,0,0,0,1401,1402,6,182,10,0,1402,380,1,0,0,0,1403,1404,3,61,23,0,1404, - 1405,1,0,0,0,1405,1406,6,183,15,0,1406,1407,6,183,11,0,1407,382,1,0,0,0, - 1408,1409,3,207,96,0,1409,1410,1,0,0,0,1410,1411,6,184,20,0,1411,1412,6, - 184,11,0,1412,1413,6,184,34,0,1413,384,1,0,0,0,1414,1415,3,83,34,0,1415, - 1416,1,0,0,0,1416,1417,6,185,21,0,1417,1418,6,185,11,0,1418,1419,6,185, - 34,0,1419,386,1,0,0,0,1420,1421,3,55,20,0,1421,1422,1,0,0,0,1422,1423,6, - 186,10,0,1423,388,1,0,0,0,1424,1425,3,57,21,0,1425,1426,1,0,0,0,1426,1427, - 6,187,10,0,1427,390,1,0,0,0,1428,1429,3,59,22,0,1429,1430,1,0,0,0,1430, - 1431,6,188,10,0,1431,392,1,0,0,0,1432,1433,3,337,161,0,1433,1434,1,0,0, - 0,1434,1435,6,189,17,0,1435,1436,6,189,11,0,1436,1437,6,189,9,0,1437,394, - 1,0,0,0,1438,1439,3,99,42,0,1439,1440,1,0,0,0,1440,1441,6,190,18,0,1441, - 1442,6,190,11,0,1442,1443,6,190,9,0,1443,396,1,0,0,0,1444,1445,3,55,20, - 0,1445,1446,1,0,0,0,1446,1447,6,191,10,0,1447,398,1,0,0,0,1448,1449,3,57, - 21,0,1449,1450,1,0,0,0,1450,1451,6,192,10,0,1451,400,1,0,0,0,1452,1453, - 3,59,22,0,1453,1454,1,0,0,0,1454,1455,6,193,10,0,1455,402,1,0,0,0,1456, - 1457,3,173,79,0,1457,1458,1,0,0,0,1458,1459,6,194,11,0,1459,1460,6,194, - 0,0,1460,1461,6,194,30,0,1461,404,1,0,0,0,1462,1463,3,169,77,0,1463,1464, - 1,0,0,0,1464,1465,6,195,11,0,1465,1466,6,195,0,0,1466,1467,6,195,31,0,1467, - 406,1,0,0,0,1468,1469,3,89,37,0,1469,1470,1,0,0,0,1470,1471,6,196,11,0, - 1471,1472,6,196,0,0,1472,1473,6,196,35,0,1473,408,1,0,0,0,1474,1475,3,61, - 23,0,1475,1476,1,0,0,0,1476,1477,6,197,15,0,1477,1478,6,197,11,0,1478,410, - 1,0,0,0,65,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,579,589,593,596,605,607,618, - 637,642,651,658,663,665,676,684,687,689,694,699,705,712,717,723,726,734, - 738,870,875,882,884,900,905,910,912,918,995,1000,1049,1053,1058,1063,1068, - 1070,1074,1076,1163,1167,1172,1315,1317,36,5,1,0,5,4,0,5,6,0,5,2,0,5,3, - 0,5,8,0,5,5,0,5,9,0,5,11,0,5,13,0,0,1,0,4,0,0,7,16,0,7,65,0,5,0,0,7,24, - 0,7,66,0,7,104,0,7,33,0,7,31,0,7,76,0,7,25,0,7,35,0,7,47,0,7,64,0,7,80, - 0,5,10,0,5,7,0,7,90,0,7,89,0,7,68,0,7,67,0,7,88,0,5,12,0,5,14,0,7,28,0]; + 2,193,7,193,2,194,7,194,2,195,7,195,2,196,7,196,2,197,7,197,2,198,7,198, + 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2, + 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,4,1,4,1,4, + 1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,5,1,5,1,5,1,5,1,5,1,5,1,5,1,6,1,6,1,6,1,6, + 1,6,1,6,1,6,1,7,1,7,1,7,1,7,1,7,1,7,1,7,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8, + 1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,10,1,10,1,10,1,10,1,10, + 1,10,1,10,1,10,1,10,1,11,1,11,1,11,1,11,1,11,1,11,1,12,1,12,1,12,1,12,1, + 12,1,12,1,12,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,14,1,14,1,14,1,14,1,14, + 1,14,1,14,1,14,1,15,1,15,1,15,1,15,1,15,1,15,1,15,1,15,1,16,1,16,1,16,1, + 16,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1,17,1,17,1,17, + 1,17,1,17,1,17,1,17,1,17,1,17,1,17,1,18,1,18,1,18,1,18,1,18,1,18,1,18,1, + 18,1,18,1,18,1,18,1,19,4,19,580,8,19,11,19,12,19,581,1,19,1,19,1,20,1,20, + 1,20,1,20,5,20,590,8,20,10,20,12,20,593,9,20,1,20,3,20,596,8,20,1,20,3, + 20,599,8,20,1,20,1,20,1,21,1,21,1,21,1,21,1,21,5,21,608,8,21,10,21,12,21, + 611,9,21,1,21,1,21,1,21,1,21,1,21,1,22,4,22,619,8,22,11,22,12,22,620,1, + 22,1,22,1,23,1,23,1,24,1,24,1,24,1,24,1,25,1,25,1,26,1,26,1,27,1,27,1,27, + 1,28,1,28,1,29,1,29,3,29,642,8,29,1,29,4,29,645,8,29,11,29,12,29,646,1, + 30,1,30,1,31,1,31,1,32,1,32,1,32,3,32,656,8,32,1,33,1,33,1,34,1,34,1,34, + 3,34,663,8,34,1,35,1,35,1,35,5,35,668,8,35,10,35,12,35,671,9,35,1,35,1, + 35,1,35,1,35,1,35,1,35,5,35,679,8,35,10,35,12,35,682,9,35,1,35,1,35,1,35, + 1,35,1,35,3,35,689,8,35,1,35,3,35,692,8,35,3,35,694,8,35,1,36,4,36,697, + 8,36,11,36,12,36,698,1,37,4,37,702,8,37,11,37,12,37,703,1,37,1,37,5,37, + 708,8,37,10,37,12,37,711,9,37,1,37,1,37,4,37,715,8,37,11,37,12,37,716,1, + 37,4,37,720,8,37,11,37,12,37,721,1,37,1,37,5,37,726,8,37,10,37,12,37,729, + 9,37,3,37,731,8,37,1,37,1,37,1,37,1,37,4,37,737,8,37,11,37,12,37,738,1, + 37,1,37,3,37,743,8,37,1,38,1,38,1,38,1,39,1,39,1,39,1,39,1,40,1,40,1,40, + 1,40,1,41,1,41,1,42,1,42,1,42,1,43,1,43,1,44,1,44,1,44,1,44,1,44,1,45,1, + 45,1,46,1,46,1,46,1,46,1,46,1,46,1,47,1,47,1,47,1,47,1,47,1,47,1,48,1,48, + 1,48,1,49,1,49,1,49,1,50,1,50,1,50,1,50,1,50,1,51,1,51,1,51,1,51,1,51,1, + 52,1,52,1,53,1,53,1,53,1,53,1,54,1,54,1,54,1,54,1,54,1,55,1,55,1,55,1,55, + 1,55,1,55,1,56,1,56,1,56,1,57,1,57,1,58,1,58,1,58,1,58,1,58,1,58,1,59,1, + 59,1,60,1,60,1,60,1,60,1,60,1,61,1,61,1,61,1,62,1,62,1,62,1,63,1,63,1,63, + 1,64,1,64,1,65,1,65,1,65,1,66,1,66,1,67,1,67,1,67,1,68,1,68,1,69,1,69,1, + 70,1,70,1,71,1,71,1,72,1,72,1,73,1,73,1,73,1,73,1,73,1,74,1,74,1,74,1,74, + 1,75,1,75,1,75,3,75,874,8,75,1,75,5,75,877,8,75,10,75,12,75,880,9,75,1, + 75,1,75,4,75,884,8,75,11,75,12,75,885,3,75,888,8,75,1,76,1,76,1,76,1,76, + 1,76,1,77,1,77,1,77,1,77,1,77,1,78,1,78,5,78,902,8,78,10,78,12,78,905,9, + 78,1,78,1,78,3,78,909,8,78,1,78,4,78,912,8,78,11,78,12,78,913,3,78,916, + 8,78,1,79,1,79,4,79,920,8,79,11,79,12,79,921,1,79,1,79,1,80,1,80,1,81,1, + 81,1,81,1,81,1,82,1,82,1,82,1,82,1,83,1,83,1,83,1,83,1,84,1,84,1,84,1,84, + 1,84,1,85,1,85,1,85,1,85,1,85,1,86,1,86,1,86,1,86,1,87,1,87,1,87,1,87,1, + 88,1,88,1,88,1,88,1,89,1,89,1,89,1,89,1,89,1,90,1,90,1,90,1,90,1,91,1,91, + 1,91,1,91,1,92,1,92,1,92,1,92,1,93,1,93,1,93,1,93,1,94,1,94,1,94,1,94,1, + 95,1,95,1,95,1,95,1,95,1,95,1,95,1,95,1,95,1,96,1,96,1,96,3,96,999,8,96, + 1,97,4,97,1002,8,97,11,97,12,97,1003,1,98,1,98,1,98,1,98,1,99,1,99,1,99, + 1,99,1,100,1,100,1,100,1,100,1,101,1,101,1,101,1,101,1,102,1,102,1,102, + 1,102,1,103,1,103,1,103,1,103,1,103,1,104,1,104,1,104,1,104,1,105,1,105, + 1,105,1,105,1,106,1,106,1,106,1,106,1,106,1,107,1,107,1,107,1,107,1,107, + 1,108,1,108,1,108,1,108,3,108,1053,8,108,1,109,1,109,3,109,1057,8,109,1, + 109,5,109,1060,8,109,10,109,12,109,1063,9,109,1,109,1,109,3,109,1067,8, + 109,1,109,4,109,1070,8,109,11,109,12,109,1071,3,109,1074,8,109,1,110,1, + 110,4,110,1078,8,110,11,110,12,110,1079,1,111,1,111,1,111,1,111,1,112,1, + 112,1,112,1,112,1,113,1,113,1,113,1,113,1,114,1,114,1,114,1,114,1,114,1, + 115,1,115,1,115,1,115,1,116,1,116,1,116,1,116,1,117,1,117,1,117,1,117,1, + 118,1,118,1,118,1,118,1,118,1,119,1,119,1,119,1,119,1,119,1,120,1,120,1, + 120,1,121,1,121,1,121,1,121,1,122,1,122,1,122,1,122,1,123,1,123,1,123,1, + 123,1,124,1,124,1,124,1,124,1,125,1,125,1,125,1,125,1,125,1,126,1,126,1, + 126,1,126,1,126,1,127,1,127,1,127,1,127,1,127,1,128,1,128,1,128,1,128,1, + 128,1,128,1,128,1,129,1,129,1,130,4,130,1165,8,130,11,130,12,130,1166,1, + 130,1,130,3,130,1171,8,130,1,130,4,130,1174,8,130,11,130,12,130,1175,1, + 131,1,131,1,131,1,131,1,132,1,132,1,132,1,132,1,133,1,133,1,133,1,133,1, + 134,1,134,1,134,1,134,1,135,1,135,1,135,1,135,1,135,1,135,1,136,1,136,1, + 136,1,136,1,137,1,137,1,137,1,137,1,138,1,138,1,138,1,138,1,139,1,139,1, + 139,1,139,1,140,1,140,1,140,1,140,1,141,1,141,1,141,1,141,1,142,1,142,1, + 142,1,142,1,142,1,143,1,143,1,143,1,143,1,143,1,144,1,144,1,144,1,144,1, + 145,1,145,1,145,1,145,1,146,1,146,1,146,1,146,1,147,1,147,1,147,1,147,1, + 147,1,148,1,148,1,148,1,148,1,149,1,149,1,149,1,149,1,149,1,150,1,150,1, + 150,1,150,1,150,1,151,1,151,1,151,1,151,1,152,1,152,1,152,1,152,1,153,1, + 153,1,153,1,153,1,154,1,154,1,154,1,154,1,155,1,155,1,155,1,155,1,156,1, + 156,1,156,1,156,1,156,1,157,1,157,1,157,1,157,1,157,1,158,1,158,1,158,1, + 158,1,159,1,159,1,159,1,159,1,160,1,160,1,160,1,160,1,161,1,161,1,161,1, + 161,1,161,1,162,1,162,1,162,1,162,1,163,1,163,1,163,1,163,1,163,4,163,1321, + 8,163,11,163,12,163,1322,1,164,1,164,1,164,1,164,1,165,1,165,1,165,1,165, + 1,166,1,166,1,166,1,166,1,167,1,167,1,167,1,167,1,167,1,168,1,168,1,168, + 1,168,1,169,1,169,1,169,1,169,1,170,1,170,1,170,1,170,1,171,1,171,1,171, + 1,171,1,171,1,172,1,172,1,172,1,172,1,173,1,173,1,173,1,173,1,174,1,174, + 1,174,1,174,1,175,1,175,1,175,1,175,1,176,1,176,1,176,1,176,1,177,1,177, + 1,177,1,177,1,177,1,177,1,178,1,178,1,178,1,178,1,179,1,179,1,179,1,179, + 1,180,1,180,1,180,1,180,1,181,1,181,1,181,1,181,1,182,1,182,1,182,1,182, + 1,183,1,183,1,183,1,183,1,184,1,184,1,184,1,184,1,184,1,185,1,185,1,185, + 1,185,1,185,1,185,1,186,1,186,1,186,1,186,1,186,1,186,1,187,1,187,1,187, + 1,187,1,188,1,188,1,188,1,188,1,189,1,189,1,189,1,189,1,190,1,190,1,190, + 1,190,1,190,1,190,1,191,1,191,1,191,1,191,1,191,1,191,1,192,1,192,1,192, + 1,192,1,193,1,193,1,193,1,193,1,194,1,194,1,194,1,194,1,195,1,195,1,195, + 1,195,1,195,1,195,1,196,1,196,1,196,1,196,1,196,1,196,1,197,1,197,1,197, + 1,197,1,197,1,197,1,198,1,198,1,198,1,198,1,198,2,609,680,0,199,15,1,17, + 2,19,3,21,4,23,5,25,6,27,7,29,8,31,9,33,10,35,11,37,12,39,13,41,14,43,15, + 45,16,47,17,49,18,51,19,53,20,55,21,57,22,59,23,61,24,63,25,65,0,67,0,69, + 0,71,0,73,0,75,0,77,0,79,0,81,0,83,0,85,26,87,27,89,28,91,29,93,30,95,31, + 97,32,99,33,101,34,103,35,105,36,107,37,109,38,111,39,113,40,115,41,117, + 42,119,43,121,44,123,45,125,46,127,47,129,48,131,49,133,50,135,51,137,52, + 139,53,141,54,143,55,145,56,147,57,149,58,151,59,153,60,155,61,157,62,159, + 63,161,0,163,0,165,64,167,65,169,66,171,67,173,0,175,68,177,69,179,70,181, + 71,183,0,185,0,187,72,189,73,191,74,193,0,195,0,197,0,199,0,201,0,203,0, + 205,75,207,0,209,76,211,0,213,0,215,77,217,78,219,79,221,0,223,0,225,0, + 227,0,229,0,231,0,233,0,235,80,237,81,239,82,241,83,243,0,245,0,247,0,249, + 0,251,0,253,0,255,84,257,0,259,85,261,86,263,87,265,0,267,0,269,88,271, + 89,273,0,275,90,277,0,279,91,281,92,283,93,285,0,287,0,289,0,291,0,293, + 0,295,0,297,0,299,0,301,0,303,94,305,95,307,96,309,0,311,0,313,0,315,0, + 317,0,319,0,321,97,323,98,325,99,327,0,329,100,331,101,333,102,335,103, + 337,0,339,0,341,104,343,105,345,106,347,107,349,0,351,0,353,0,355,0,357, + 0,359,0,361,0,363,108,365,109,367,110,369,0,371,0,373,0,375,0,377,111,379, + 112,381,113,383,0,385,0,387,0,389,114,391,115,393,116,395,0,397,0,399,117, + 401,118,403,119,405,0,407,0,409,0,411,0,15,0,1,2,3,4,5,6,7,8,9,10,11,12, + 13,14,35,2,0,68,68,100,100,2,0,73,73,105,105,2,0,83,83,115,115,2,0,69,69, + 101,101,2,0,67,67,99,99,2,0,84,84,116,116,2,0,82,82,114,114,2,0,79,79,111, + 111,2,0,80,80,112,112,2,0,78,78,110,110,2,0,72,72,104,104,2,0,86,86,118, + 118,2,0,65,65,97,97,2,0,76,76,108,108,2,0,88,88,120,120,2,0,70,70,102,102, + 2,0,77,77,109,109,2,0,71,71,103,103,2,0,75,75,107,107,2,0,87,87,119,119, + 2,0,85,85,117,117,6,0,9,10,13,13,32,32,47,47,91,91,93,93,2,0,10,10,13,13, + 3,0,9,10,13,13,32,32,1,0,48,57,2,0,65,90,97,122,8,0,34,34,78,78,82,82,84, + 84,92,92,110,110,114,114,116,116,4,0,10,10,13,13,34,34,92,92,2,0,43,43, + 45,45,1,0,96,96,2,0,66,66,98,98,2,0,89,89,121,121,11,0,9,10,13,13,32,32, + 34,34,44,44,47,47,58,58,61,61,91,91,93,93,124,124,2,0,42,42,47,47,11,0, + 9,10,13,13,32,32,34,35,44,44,47,47,58,58,60,60,62,63,92,92,124,124,1512, + 0,15,1,0,0,0,0,17,1,0,0,0,0,19,1,0,0,0,0,21,1,0,0,0,0,23,1,0,0,0,0,25,1, + 0,0,0,0,27,1,0,0,0,0,29,1,0,0,0,0,31,1,0,0,0,0,33,1,0,0,0,0,35,1,0,0,0, + 0,37,1,0,0,0,0,39,1,0,0,0,0,41,1,0,0,0,0,43,1,0,0,0,0,45,1,0,0,0,0,47,1, + 0,0,0,0,49,1,0,0,0,0,51,1,0,0,0,0,53,1,0,0,0,0,55,1,0,0,0,0,57,1,0,0,0, + 0,59,1,0,0,0,0,61,1,0,0,0,1,63,1,0,0,0,1,85,1,0,0,0,1,87,1,0,0,0,1,89,1, + 0,0,0,1,91,1,0,0,0,1,93,1,0,0,0,1,95,1,0,0,0,1,97,1,0,0,0,1,99,1,0,0,0, + 1,101,1,0,0,0,1,103,1,0,0,0,1,105,1,0,0,0,1,107,1,0,0,0,1,109,1,0,0,0,1, + 111,1,0,0,0,1,113,1,0,0,0,1,115,1,0,0,0,1,117,1,0,0,0,1,119,1,0,0,0,1,121, + 1,0,0,0,1,123,1,0,0,0,1,125,1,0,0,0,1,127,1,0,0,0,1,129,1,0,0,0,1,131,1, + 0,0,0,1,133,1,0,0,0,1,135,1,0,0,0,1,137,1,0,0,0,1,139,1,0,0,0,1,141,1,0, + 0,0,1,143,1,0,0,0,1,145,1,0,0,0,1,147,1,0,0,0,1,149,1,0,0,0,1,151,1,0,0, + 0,1,153,1,0,0,0,1,155,1,0,0,0,1,157,1,0,0,0,1,159,1,0,0,0,1,161,1,0,0,0, + 1,163,1,0,0,0,1,165,1,0,0,0,1,167,1,0,0,0,1,169,1,0,0,0,1,171,1,0,0,0,1, + 175,1,0,0,0,1,177,1,0,0,0,1,179,1,0,0,0,1,181,1,0,0,0,2,183,1,0,0,0,2,185, + 1,0,0,0,2,187,1,0,0,0,2,189,1,0,0,0,2,191,1,0,0,0,3,193,1,0,0,0,3,195,1, + 0,0,0,3,197,1,0,0,0,3,199,1,0,0,0,3,201,1,0,0,0,3,203,1,0,0,0,3,205,1,0, + 0,0,3,209,1,0,0,0,3,211,1,0,0,0,3,213,1,0,0,0,3,215,1,0,0,0,3,217,1,0,0, + 0,3,219,1,0,0,0,4,221,1,0,0,0,4,223,1,0,0,0,4,225,1,0,0,0,4,227,1,0,0,0, + 4,229,1,0,0,0,4,235,1,0,0,0,4,237,1,0,0,0,4,239,1,0,0,0,4,241,1,0,0,0,5, + 243,1,0,0,0,5,245,1,0,0,0,5,247,1,0,0,0,5,249,1,0,0,0,5,251,1,0,0,0,5,253, + 1,0,0,0,5,255,1,0,0,0,5,257,1,0,0,0,5,259,1,0,0,0,5,261,1,0,0,0,5,263,1, + 0,0,0,6,265,1,0,0,0,6,267,1,0,0,0,6,269,1,0,0,0,6,271,1,0,0,0,6,275,1,0, + 0,0,6,277,1,0,0,0,6,279,1,0,0,0,6,281,1,0,0,0,6,283,1,0,0,0,7,285,1,0,0, + 0,7,287,1,0,0,0,7,289,1,0,0,0,7,291,1,0,0,0,7,293,1,0,0,0,7,295,1,0,0,0, + 7,297,1,0,0,0,7,299,1,0,0,0,7,301,1,0,0,0,7,303,1,0,0,0,7,305,1,0,0,0,7, + 307,1,0,0,0,8,309,1,0,0,0,8,311,1,0,0,0,8,313,1,0,0,0,8,315,1,0,0,0,8,317, + 1,0,0,0,8,319,1,0,0,0,8,321,1,0,0,0,8,323,1,0,0,0,8,325,1,0,0,0,9,327,1, + 0,0,0,9,329,1,0,0,0,9,331,1,0,0,0,9,333,1,0,0,0,9,335,1,0,0,0,10,337,1, + 0,0,0,10,339,1,0,0,0,10,341,1,0,0,0,10,343,1,0,0,0,10,345,1,0,0,0,10,347, + 1,0,0,0,11,349,1,0,0,0,11,351,1,0,0,0,11,353,1,0,0,0,11,355,1,0,0,0,11, + 357,1,0,0,0,11,359,1,0,0,0,11,361,1,0,0,0,11,363,1,0,0,0,11,365,1,0,0,0, + 11,367,1,0,0,0,12,369,1,0,0,0,12,371,1,0,0,0,12,373,1,0,0,0,12,375,1,0, + 0,0,12,377,1,0,0,0,12,379,1,0,0,0,12,381,1,0,0,0,13,383,1,0,0,0,13,385, + 1,0,0,0,13,387,1,0,0,0,13,389,1,0,0,0,13,391,1,0,0,0,13,393,1,0,0,0,14, + 395,1,0,0,0,14,397,1,0,0,0,14,399,1,0,0,0,14,401,1,0,0,0,14,403,1,0,0,0, + 14,405,1,0,0,0,14,407,1,0,0,0,14,409,1,0,0,0,14,411,1,0,0,0,15,413,1,0, + 0,0,17,423,1,0,0,0,19,430,1,0,0,0,21,439,1,0,0,0,23,446,1,0,0,0,25,456, + 1,0,0,0,27,463,1,0,0,0,29,470,1,0,0,0,31,477,1,0,0,0,33,485,1,0,0,0,35, + 497,1,0,0,0,37,506,1,0,0,0,39,512,1,0,0,0,41,519,1,0,0,0,43,526,1,0,0,0, + 45,534,1,0,0,0,47,542,1,0,0,0,49,557,1,0,0,0,51,567,1,0,0,0,53,579,1,0, + 0,0,55,585,1,0,0,0,57,602,1,0,0,0,59,618,1,0,0,0,61,624,1,0,0,0,63,626, + 1,0,0,0,65,630,1,0,0,0,67,632,1,0,0,0,69,634,1,0,0,0,71,637,1,0,0,0,73, + 639,1,0,0,0,75,648,1,0,0,0,77,650,1,0,0,0,79,655,1,0,0,0,81,657,1,0,0,0, + 83,662,1,0,0,0,85,693,1,0,0,0,87,696,1,0,0,0,89,742,1,0,0,0,91,744,1,0, + 0,0,93,747,1,0,0,0,95,751,1,0,0,0,97,755,1,0,0,0,99,757,1,0,0,0,101,760, + 1,0,0,0,103,762,1,0,0,0,105,767,1,0,0,0,107,769,1,0,0,0,109,775,1,0,0,0, + 111,781,1,0,0,0,113,784,1,0,0,0,115,787,1,0,0,0,117,792,1,0,0,0,119,797, + 1,0,0,0,121,799,1,0,0,0,123,803,1,0,0,0,125,808,1,0,0,0,127,814,1,0,0,0, + 129,817,1,0,0,0,131,819,1,0,0,0,133,825,1,0,0,0,135,827,1,0,0,0,137,832, + 1,0,0,0,139,835,1,0,0,0,141,838,1,0,0,0,143,841,1,0,0,0,145,843,1,0,0,0, + 147,846,1,0,0,0,149,848,1,0,0,0,151,851,1,0,0,0,153,853,1,0,0,0,155,855, + 1,0,0,0,157,857,1,0,0,0,159,859,1,0,0,0,161,861,1,0,0,0,163,866,1,0,0,0, + 165,887,1,0,0,0,167,889,1,0,0,0,169,894,1,0,0,0,171,915,1,0,0,0,173,917, + 1,0,0,0,175,925,1,0,0,0,177,927,1,0,0,0,179,931,1,0,0,0,181,935,1,0,0,0, + 183,939,1,0,0,0,185,944,1,0,0,0,187,949,1,0,0,0,189,953,1,0,0,0,191,957, + 1,0,0,0,193,961,1,0,0,0,195,966,1,0,0,0,197,970,1,0,0,0,199,974,1,0,0,0, + 201,978,1,0,0,0,203,982,1,0,0,0,205,986,1,0,0,0,207,998,1,0,0,0,209,1001, + 1,0,0,0,211,1005,1,0,0,0,213,1009,1,0,0,0,215,1013,1,0,0,0,217,1017,1,0, + 0,0,219,1021,1,0,0,0,221,1025,1,0,0,0,223,1030,1,0,0,0,225,1034,1,0,0,0, + 227,1038,1,0,0,0,229,1043,1,0,0,0,231,1052,1,0,0,0,233,1073,1,0,0,0,235, + 1077,1,0,0,0,237,1081,1,0,0,0,239,1085,1,0,0,0,241,1089,1,0,0,0,243,1093, + 1,0,0,0,245,1098,1,0,0,0,247,1102,1,0,0,0,249,1106,1,0,0,0,251,1110,1,0, + 0,0,253,1115,1,0,0,0,255,1120,1,0,0,0,257,1123,1,0,0,0,259,1127,1,0,0,0, + 261,1131,1,0,0,0,263,1135,1,0,0,0,265,1139,1,0,0,0,267,1144,1,0,0,0,269, + 1149,1,0,0,0,271,1154,1,0,0,0,273,1161,1,0,0,0,275,1170,1,0,0,0,277,1177, + 1,0,0,0,279,1181,1,0,0,0,281,1185,1,0,0,0,283,1189,1,0,0,0,285,1193,1,0, + 0,0,287,1199,1,0,0,0,289,1203,1,0,0,0,291,1207,1,0,0,0,293,1211,1,0,0,0, + 295,1215,1,0,0,0,297,1219,1,0,0,0,299,1223,1,0,0,0,301,1228,1,0,0,0,303, + 1233,1,0,0,0,305,1237,1,0,0,0,307,1241,1,0,0,0,309,1245,1,0,0,0,311,1250, + 1,0,0,0,313,1254,1,0,0,0,315,1259,1,0,0,0,317,1264,1,0,0,0,319,1268,1,0, + 0,0,321,1272,1,0,0,0,323,1276,1,0,0,0,325,1280,1,0,0,0,327,1284,1,0,0,0, + 329,1289,1,0,0,0,331,1294,1,0,0,0,333,1298,1,0,0,0,335,1302,1,0,0,0,337, + 1306,1,0,0,0,339,1311,1,0,0,0,341,1320,1,0,0,0,343,1324,1,0,0,0,345,1328, + 1,0,0,0,347,1332,1,0,0,0,349,1336,1,0,0,0,351,1341,1,0,0,0,353,1345,1,0, + 0,0,355,1349,1,0,0,0,357,1353,1,0,0,0,359,1358,1,0,0,0,361,1362,1,0,0,0, + 363,1366,1,0,0,0,365,1370,1,0,0,0,367,1374,1,0,0,0,369,1378,1,0,0,0,371, + 1384,1,0,0,0,373,1388,1,0,0,0,375,1392,1,0,0,0,377,1396,1,0,0,0,379,1400, + 1,0,0,0,381,1404,1,0,0,0,383,1408,1,0,0,0,385,1413,1,0,0,0,387,1419,1,0, + 0,0,389,1425,1,0,0,0,391,1429,1,0,0,0,393,1433,1,0,0,0,395,1437,1,0,0,0, + 397,1443,1,0,0,0,399,1449,1,0,0,0,401,1453,1,0,0,0,403,1457,1,0,0,0,405, + 1461,1,0,0,0,407,1467,1,0,0,0,409,1473,1,0,0,0,411,1479,1,0,0,0,413,414, + 7,0,0,0,414,415,7,1,0,0,415,416,7,2,0,0,416,417,7,2,0,0,417,418,7,3,0,0, + 418,419,7,4,0,0,419,420,7,5,0,0,420,421,1,0,0,0,421,422,6,0,0,0,422,16, + 1,0,0,0,423,424,7,0,0,0,424,425,7,6,0,0,425,426,7,7,0,0,426,427,7,8,0,0, + 427,428,1,0,0,0,428,429,6,1,1,0,429,18,1,0,0,0,430,431,7,3,0,0,431,432, + 7,9,0,0,432,433,7,6,0,0,433,434,7,1,0,0,434,435,7,4,0,0,435,436,7,10,0, + 0,436,437,1,0,0,0,437,438,6,2,2,0,438,20,1,0,0,0,439,440,7,3,0,0,440,441, + 7,11,0,0,441,442,7,12,0,0,442,443,7,13,0,0,443,444,1,0,0,0,444,445,6,3, + 0,0,445,22,1,0,0,0,446,447,7,3,0,0,447,448,7,14,0,0,448,449,7,8,0,0,449, + 450,7,13,0,0,450,451,7,12,0,0,451,452,7,1,0,0,452,453,7,9,0,0,453,454,1, + 0,0,0,454,455,6,4,3,0,455,24,1,0,0,0,456,457,7,15,0,0,457,458,7,6,0,0,458, + 459,7,7,0,0,459,460,7,16,0,0,460,461,1,0,0,0,461,462,6,5,4,0,462,26,1,0, + 0,0,463,464,7,17,0,0,464,465,7,6,0,0,465,466,7,7,0,0,466,467,7,18,0,0,467, + 468,1,0,0,0,468,469,6,6,0,0,469,28,1,0,0,0,470,471,7,18,0,0,471,472,7,3, + 0,0,472,473,7,3,0,0,473,474,7,8,0,0,474,475,1,0,0,0,475,476,6,7,1,0,476, + 30,1,0,0,0,477,478,7,13,0,0,478,479,7,1,0,0,479,480,7,16,0,0,480,481,7, + 1,0,0,481,482,7,5,0,0,482,483,1,0,0,0,483,484,6,8,0,0,484,32,1,0,0,0,485, + 486,7,16,0,0,486,487,7,11,0,0,487,488,5,95,0,0,488,489,7,3,0,0,489,490, + 7,14,0,0,490,491,7,8,0,0,491,492,7,12,0,0,492,493,7,9,0,0,493,494,7,0,0, + 0,494,495,1,0,0,0,495,496,6,9,5,0,496,34,1,0,0,0,497,498,7,6,0,0,498,499, + 7,3,0,0,499,500,7,9,0,0,500,501,7,12,0,0,501,502,7,16,0,0,502,503,7,3,0, + 0,503,504,1,0,0,0,504,505,6,10,6,0,505,36,1,0,0,0,506,507,7,6,0,0,507,508, + 7,7,0,0,508,509,7,19,0,0,509,510,1,0,0,0,510,511,6,11,0,0,511,38,1,0,0, + 0,512,513,7,2,0,0,513,514,7,10,0,0,514,515,7,7,0,0,515,516,7,19,0,0,516, + 517,1,0,0,0,517,518,6,12,7,0,518,40,1,0,0,0,519,520,7,2,0,0,520,521,7,7, + 0,0,521,522,7,6,0,0,522,523,7,5,0,0,523,524,1,0,0,0,524,525,6,13,0,0,525, + 42,1,0,0,0,526,527,7,2,0,0,527,528,7,5,0,0,528,529,7,12,0,0,529,530,7,5, + 0,0,530,531,7,2,0,0,531,532,1,0,0,0,532,533,6,14,0,0,533,44,1,0,0,0,534, + 535,7,19,0,0,535,536,7,10,0,0,536,537,7,3,0,0,537,538,7,6,0,0,538,539,7, + 3,0,0,539,540,1,0,0,0,540,541,6,15,0,0,541,46,1,0,0,0,542,543,4,16,0,0, + 543,544,7,1,0,0,544,545,7,9,0,0,545,546,7,13,0,0,546,547,7,1,0,0,547,548, + 7,9,0,0,548,549,7,3,0,0,549,550,7,2,0,0,550,551,7,5,0,0,551,552,7,12,0, + 0,552,553,7,5,0,0,553,554,7,2,0,0,554,555,1,0,0,0,555,556,6,16,0,0,556, + 48,1,0,0,0,557,558,4,17,1,0,558,559,7,13,0,0,559,560,7,7,0,0,560,561,7, + 7,0,0,561,562,7,18,0,0,562,563,7,20,0,0,563,564,7,8,0,0,564,565,1,0,0,0, + 565,566,6,17,8,0,566,50,1,0,0,0,567,568,4,18,2,0,568,569,7,16,0,0,569,570, + 7,3,0,0,570,571,7,5,0,0,571,572,7,6,0,0,572,573,7,1,0,0,573,574,7,4,0,0, + 574,575,7,2,0,0,575,576,1,0,0,0,576,577,6,18,9,0,577,52,1,0,0,0,578,580, + 8,21,0,0,579,578,1,0,0,0,580,581,1,0,0,0,581,579,1,0,0,0,581,582,1,0,0, + 0,582,583,1,0,0,0,583,584,6,19,0,0,584,54,1,0,0,0,585,586,5,47,0,0,586, + 587,5,47,0,0,587,591,1,0,0,0,588,590,8,22,0,0,589,588,1,0,0,0,590,593,1, + 0,0,0,591,589,1,0,0,0,591,592,1,0,0,0,592,595,1,0,0,0,593,591,1,0,0,0,594, + 596,5,13,0,0,595,594,1,0,0,0,595,596,1,0,0,0,596,598,1,0,0,0,597,599,5, + 10,0,0,598,597,1,0,0,0,598,599,1,0,0,0,599,600,1,0,0,0,600,601,6,20,10, + 0,601,56,1,0,0,0,602,603,5,47,0,0,603,604,5,42,0,0,604,609,1,0,0,0,605, + 608,3,57,21,0,606,608,9,0,0,0,607,605,1,0,0,0,607,606,1,0,0,0,608,611,1, + 0,0,0,609,610,1,0,0,0,609,607,1,0,0,0,610,612,1,0,0,0,611,609,1,0,0,0,612, + 613,5,42,0,0,613,614,5,47,0,0,614,615,1,0,0,0,615,616,6,21,10,0,616,58, + 1,0,0,0,617,619,7,23,0,0,618,617,1,0,0,0,619,620,1,0,0,0,620,618,1,0,0, + 0,620,621,1,0,0,0,621,622,1,0,0,0,622,623,6,22,10,0,623,60,1,0,0,0,624, + 625,5,58,0,0,625,62,1,0,0,0,626,627,5,124,0,0,627,628,1,0,0,0,628,629,6, + 24,11,0,629,64,1,0,0,0,630,631,7,24,0,0,631,66,1,0,0,0,632,633,7,25,0,0, + 633,68,1,0,0,0,634,635,5,92,0,0,635,636,7,26,0,0,636,70,1,0,0,0,637,638, + 8,27,0,0,638,72,1,0,0,0,639,641,7,3,0,0,640,642,7,28,0,0,641,640,1,0,0, + 0,641,642,1,0,0,0,642,644,1,0,0,0,643,645,3,65,25,0,644,643,1,0,0,0,645, + 646,1,0,0,0,646,644,1,0,0,0,646,647,1,0,0,0,647,74,1,0,0,0,648,649,5,64, + 0,0,649,76,1,0,0,0,650,651,5,96,0,0,651,78,1,0,0,0,652,656,8,29,0,0,653, + 654,5,96,0,0,654,656,5,96,0,0,655,652,1,0,0,0,655,653,1,0,0,0,656,80,1, + 0,0,0,657,658,5,95,0,0,658,82,1,0,0,0,659,663,3,67,26,0,660,663,3,65,25, + 0,661,663,3,81,33,0,662,659,1,0,0,0,662,660,1,0,0,0,662,661,1,0,0,0,663, + 84,1,0,0,0,664,669,5,34,0,0,665,668,3,69,27,0,666,668,3,71,28,0,667,665, + 1,0,0,0,667,666,1,0,0,0,668,671,1,0,0,0,669,667,1,0,0,0,669,670,1,0,0,0, + 670,672,1,0,0,0,671,669,1,0,0,0,672,694,5,34,0,0,673,674,5,34,0,0,674,675, + 5,34,0,0,675,676,5,34,0,0,676,680,1,0,0,0,677,679,8,22,0,0,678,677,1,0, + 0,0,679,682,1,0,0,0,680,681,1,0,0,0,680,678,1,0,0,0,681,683,1,0,0,0,682, + 680,1,0,0,0,683,684,5,34,0,0,684,685,5,34,0,0,685,686,5,34,0,0,686,688, + 1,0,0,0,687,689,5,34,0,0,688,687,1,0,0,0,688,689,1,0,0,0,689,691,1,0,0, + 0,690,692,5,34,0,0,691,690,1,0,0,0,691,692,1,0,0,0,692,694,1,0,0,0,693, + 664,1,0,0,0,693,673,1,0,0,0,694,86,1,0,0,0,695,697,3,65,25,0,696,695,1, + 0,0,0,697,698,1,0,0,0,698,696,1,0,0,0,698,699,1,0,0,0,699,88,1,0,0,0,700, + 702,3,65,25,0,701,700,1,0,0,0,702,703,1,0,0,0,703,701,1,0,0,0,703,704,1, + 0,0,0,704,705,1,0,0,0,705,709,3,105,45,0,706,708,3,65,25,0,707,706,1,0, + 0,0,708,711,1,0,0,0,709,707,1,0,0,0,709,710,1,0,0,0,710,743,1,0,0,0,711, + 709,1,0,0,0,712,714,3,105,45,0,713,715,3,65,25,0,714,713,1,0,0,0,715,716, + 1,0,0,0,716,714,1,0,0,0,716,717,1,0,0,0,717,743,1,0,0,0,718,720,3,65,25, + 0,719,718,1,0,0,0,720,721,1,0,0,0,721,719,1,0,0,0,721,722,1,0,0,0,722,730, + 1,0,0,0,723,727,3,105,45,0,724,726,3,65,25,0,725,724,1,0,0,0,726,729,1, + 0,0,0,727,725,1,0,0,0,727,728,1,0,0,0,728,731,1,0,0,0,729,727,1,0,0,0,730, + 723,1,0,0,0,730,731,1,0,0,0,731,732,1,0,0,0,732,733,3,73,29,0,733,743,1, + 0,0,0,734,736,3,105,45,0,735,737,3,65,25,0,736,735,1,0,0,0,737,738,1,0, + 0,0,738,736,1,0,0,0,738,739,1,0,0,0,739,740,1,0,0,0,740,741,3,73,29,0,741, + 743,1,0,0,0,742,701,1,0,0,0,742,712,1,0,0,0,742,719,1,0,0,0,742,734,1,0, + 0,0,743,90,1,0,0,0,744,745,7,30,0,0,745,746,7,31,0,0,746,92,1,0,0,0,747, + 748,7,12,0,0,748,749,7,9,0,0,749,750,7,0,0,0,750,94,1,0,0,0,751,752,7,12, + 0,0,752,753,7,2,0,0,753,754,7,4,0,0,754,96,1,0,0,0,755,756,5,61,0,0,756, + 98,1,0,0,0,757,758,5,58,0,0,758,759,5,58,0,0,759,100,1,0,0,0,760,761,5, + 44,0,0,761,102,1,0,0,0,762,763,7,0,0,0,763,764,7,3,0,0,764,765,7,2,0,0, + 765,766,7,4,0,0,766,104,1,0,0,0,767,768,5,46,0,0,768,106,1,0,0,0,769,770, + 7,15,0,0,770,771,7,12,0,0,771,772,7,13,0,0,772,773,7,2,0,0,773,774,7,3, + 0,0,774,108,1,0,0,0,775,776,7,15,0,0,776,777,7,1,0,0,777,778,7,6,0,0,778, + 779,7,2,0,0,779,780,7,5,0,0,780,110,1,0,0,0,781,782,7,1,0,0,782,783,7,9, + 0,0,783,112,1,0,0,0,784,785,7,1,0,0,785,786,7,2,0,0,786,114,1,0,0,0,787, + 788,7,13,0,0,788,789,7,12,0,0,789,790,7,2,0,0,790,791,7,5,0,0,791,116,1, + 0,0,0,792,793,7,13,0,0,793,794,7,1,0,0,794,795,7,18,0,0,795,796,7,3,0,0, + 796,118,1,0,0,0,797,798,5,40,0,0,798,120,1,0,0,0,799,800,7,9,0,0,800,801, + 7,7,0,0,801,802,7,5,0,0,802,122,1,0,0,0,803,804,7,9,0,0,804,805,7,20,0, + 0,805,806,7,13,0,0,806,807,7,13,0,0,807,124,1,0,0,0,808,809,7,9,0,0,809, + 810,7,20,0,0,810,811,7,13,0,0,811,812,7,13,0,0,812,813,7,2,0,0,813,126, + 1,0,0,0,814,815,7,7,0,0,815,816,7,6,0,0,816,128,1,0,0,0,817,818,5,63,0, + 0,818,130,1,0,0,0,819,820,7,6,0,0,820,821,7,13,0,0,821,822,7,1,0,0,822, + 823,7,18,0,0,823,824,7,3,0,0,824,132,1,0,0,0,825,826,5,41,0,0,826,134,1, + 0,0,0,827,828,7,5,0,0,828,829,7,6,0,0,829,830,7,20,0,0,830,831,7,3,0,0, + 831,136,1,0,0,0,832,833,5,61,0,0,833,834,5,61,0,0,834,138,1,0,0,0,835,836, + 5,61,0,0,836,837,5,126,0,0,837,140,1,0,0,0,838,839,5,33,0,0,839,840,5,61, + 0,0,840,142,1,0,0,0,841,842,5,60,0,0,842,144,1,0,0,0,843,844,5,60,0,0,844, + 845,5,61,0,0,845,146,1,0,0,0,846,847,5,62,0,0,847,148,1,0,0,0,848,849,5, + 62,0,0,849,850,5,61,0,0,850,150,1,0,0,0,851,852,5,43,0,0,852,152,1,0,0, + 0,853,854,5,45,0,0,854,154,1,0,0,0,855,856,5,42,0,0,856,156,1,0,0,0,857, + 858,5,47,0,0,858,158,1,0,0,0,859,860,5,37,0,0,860,160,1,0,0,0,861,862,4, + 73,3,0,862,863,3,61,23,0,863,864,1,0,0,0,864,865,6,73,12,0,865,162,1,0, + 0,0,866,867,3,45,15,0,867,868,1,0,0,0,868,869,6,74,13,0,869,164,1,0,0,0, + 870,873,3,129,57,0,871,874,3,67,26,0,872,874,3,81,33,0,873,871,1,0,0,0, + 873,872,1,0,0,0,874,878,1,0,0,0,875,877,3,83,34,0,876,875,1,0,0,0,877,880, + 1,0,0,0,878,876,1,0,0,0,878,879,1,0,0,0,879,888,1,0,0,0,880,878,1,0,0,0, + 881,883,3,129,57,0,882,884,3,65,25,0,883,882,1,0,0,0,884,885,1,0,0,0,885, + 883,1,0,0,0,885,886,1,0,0,0,886,888,1,0,0,0,887,870,1,0,0,0,887,881,1,0, + 0,0,888,166,1,0,0,0,889,890,5,91,0,0,890,891,1,0,0,0,891,892,6,76,0,0,892, + 893,6,76,0,0,893,168,1,0,0,0,894,895,5,93,0,0,895,896,1,0,0,0,896,897,6, + 77,11,0,897,898,6,77,11,0,898,170,1,0,0,0,899,903,3,67,26,0,900,902,3,83, + 34,0,901,900,1,0,0,0,902,905,1,0,0,0,903,901,1,0,0,0,903,904,1,0,0,0,904, + 916,1,0,0,0,905,903,1,0,0,0,906,909,3,81,33,0,907,909,3,75,30,0,908,906, + 1,0,0,0,908,907,1,0,0,0,909,911,1,0,0,0,910,912,3,83,34,0,911,910,1,0,0, + 0,912,913,1,0,0,0,913,911,1,0,0,0,913,914,1,0,0,0,914,916,1,0,0,0,915,899, + 1,0,0,0,915,908,1,0,0,0,916,172,1,0,0,0,917,919,3,77,31,0,918,920,3,79, + 32,0,919,918,1,0,0,0,920,921,1,0,0,0,921,919,1,0,0,0,921,922,1,0,0,0,922, + 923,1,0,0,0,923,924,3,77,31,0,924,174,1,0,0,0,925,926,3,173,79,0,926,176, + 1,0,0,0,927,928,3,55,20,0,928,929,1,0,0,0,929,930,6,81,10,0,930,178,1,0, + 0,0,931,932,3,57,21,0,932,933,1,0,0,0,933,934,6,82,10,0,934,180,1,0,0,0, + 935,936,3,59,22,0,936,937,1,0,0,0,937,938,6,83,10,0,938,182,1,0,0,0,939, + 940,3,167,76,0,940,941,1,0,0,0,941,942,6,84,14,0,942,943,6,84,15,0,943, + 184,1,0,0,0,944,945,3,63,24,0,945,946,1,0,0,0,946,947,6,85,16,0,947,948, + 6,85,11,0,948,186,1,0,0,0,949,950,3,59,22,0,950,951,1,0,0,0,951,952,6,86, + 10,0,952,188,1,0,0,0,953,954,3,55,20,0,954,955,1,0,0,0,955,956,6,87,10, + 0,956,190,1,0,0,0,957,958,3,57,21,0,958,959,1,0,0,0,959,960,6,88,10,0,960, + 192,1,0,0,0,961,962,3,63,24,0,962,963,1,0,0,0,963,964,6,89,16,0,964,965, + 6,89,11,0,965,194,1,0,0,0,966,967,3,167,76,0,967,968,1,0,0,0,968,969,6, + 90,14,0,969,196,1,0,0,0,970,971,3,169,77,0,971,972,1,0,0,0,972,973,6,91, + 17,0,973,198,1,0,0,0,974,975,3,61,23,0,975,976,1,0,0,0,976,977,6,92,12, + 0,977,200,1,0,0,0,978,979,3,101,43,0,979,980,1,0,0,0,980,981,6,93,18,0, + 981,202,1,0,0,0,982,983,3,97,41,0,983,984,1,0,0,0,984,985,6,94,19,0,985, + 204,1,0,0,0,986,987,7,16,0,0,987,988,7,3,0,0,988,989,7,5,0,0,989,990,7, + 12,0,0,990,991,7,0,0,0,991,992,7,12,0,0,992,993,7,5,0,0,993,994,7,12,0, + 0,994,206,1,0,0,0,995,999,8,32,0,0,996,997,5,47,0,0,997,999,8,33,0,0,998, + 995,1,0,0,0,998,996,1,0,0,0,999,208,1,0,0,0,1000,1002,3,207,96,0,1001,1000, + 1,0,0,0,1002,1003,1,0,0,0,1003,1001,1,0,0,0,1003,1004,1,0,0,0,1004,210, + 1,0,0,0,1005,1006,3,209,97,0,1006,1007,1,0,0,0,1007,1008,6,98,20,0,1008, + 212,1,0,0,0,1009,1010,3,85,35,0,1010,1011,1,0,0,0,1011,1012,6,99,21,0,1012, + 214,1,0,0,0,1013,1014,3,55,20,0,1014,1015,1,0,0,0,1015,1016,6,100,10,0, + 1016,216,1,0,0,0,1017,1018,3,57,21,0,1018,1019,1,0,0,0,1019,1020,6,101, + 10,0,1020,218,1,0,0,0,1021,1022,3,59,22,0,1022,1023,1,0,0,0,1023,1024,6, + 102,10,0,1024,220,1,0,0,0,1025,1026,3,63,24,0,1026,1027,1,0,0,0,1027,1028, + 6,103,16,0,1028,1029,6,103,11,0,1029,222,1,0,0,0,1030,1031,3,105,45,0,1031, + 1032,1,0,0,0,1032,1033,6,104,22,0,1033,224,1,0,0,0,1034,1035,3,101,43,0, + 1035,1036,1,0,0,0,1036,1037,6,105,18,0,1037,226,1,0,0,0,1038,1039,4,106, + 4,0,1039,1040,3,129,57,0,1040,1041,1,0,0,0,1041,1042,6,106,23,0,1042,228, + 1,0,0,0,1043,1044,4,107,5,0,1044,1045,3,165,75,0,1045,1046,1,0,0,0,1046, + 1047,6,107,24,0,1047,230,1,0,0,0,1048,1053,3,67,26,0,1049,1053,3,65,25, + 0,1050,1053,3,81,33,0,1051,1053,3,155,70,0,1052,1048,1,0,0,0,1052,1049, + 1,0,0,0,1052,1050,1,0,0,0,1052,1051,1,0,0,0,1053,232,1,0,0,0,1054,1057, + 3,67,26,0,1055,1057,3,155,70,0,1056,1054,1,0,0,0,1056,1055,1,0,0,0,1057, + 1061,1,0,0,0,1058,1060,3,231,108,0,1059,1058,1,0,0,0,1060,1063,1,0,0,0, + 1061,1059,1,0,0,0,1061,1062,1,0,0,0,1062,1074,1,0,0,0,1063,1061,1,0,0,0, + 1064,1067,3,81,33,0,1065,1067,3,75,30,0,1066,1064,1,0,0,0,1066,1065,1,0, + 0,0,1067,1069,1,0,0,0,1068,1070,3,231,108,0,1069,1068,1,0,0,0,1070,1071, + 1,0,0,0,1071,1069,1,0,0,0,1071,1072,1,0,0,0,1072,1074,1,0,0,0,1073,1056, + 1,0,0,0,1073,1066,1,0,0,0,1074,234,1,0,0,0,1075,1078,3,233,109,0,1076,1078, + 3,173,79,0,1077,1075,1,0,0,0,1077,1076,1,0,0,0,1078,1079,1,0,0,0,1079,1077, + 1,0,0,0,1079,1080,1,0,0,0,1080,236,1,0,0,0,1081,1082,3,55,20,0,1082,1083, + 1,0,0,0,1083,1084,6,111,10,0,1084,238,1,0,0,0,1085,1086,3,57,21,0,1086, + 1087,1,0,0,0,1087,1088,6,112,10,0,1088,240,1,0,0,0,1089,1090,3,59,22,0, + 1090,1091,1,0,0,0,1091,1092,6,113,10,0,1092,242,1,0,0,0,1093,1094,3,63, + 24,0,1094,1095,1,0,0,0,1095,1096,6,114,16,0,1096,1097,6,114,11,0,1097,244, + 1,0,0,0,1098,1099,3,97,41,0,1099,1100,1,0,0,0,1100,1101,6,115,19,0,1101, + 246,1,0,0,0,1102,1103,3,101,43,0,1103,1104,1,0,0,0,1104,1105,6,116,18,0, + 1105,248,1,0,0,0,1106,1107,3,105,45,0,1107,1108,1,0,0,0,1108,1109,6,117, + 22,0,1109,250,1,0,0,0,1110,1111,4,118,6,0,1111,1112,3,129,57,0,1112,1113, + 1,0,0,0,1113,1114,6,118,23,0,1114,252,1,0,0,0,1115,1116,4,119,7,0,1116, + 1117,3,165,75,0,1117,1118,1,0,0,0,1118,1119,6,119,24,0,1119,254,1,0,0,0, + 1120,1121,7,12,0,0,1121,1122,7,2,0,0,1122,256,1,0,0,0,1123,1124,3,235,110, + 0,1124,1125,1,0,0,0,1125,1126,6,121,25,0,1126,258,1,0,0,0,1127,1128,3,55, + 20,0,1128,1129,1,0,0,0,1129,1130,6,122,10,0,1130,260,1,0,0,0,1131,1132, + 3,57,21,0,1132,1133,1,0,0,0,1133,1134,6,123,10,0,1134,262,1,0,0,0,1135, + 1136,3,59,22,0,1136,1137,1,0,0,0,1137,1138,6,124,10,0,1138,264,1,0,0,0, + 1139,1140,3,63,24,0,1140,1141,1,0,0,0,1141,1142,6,125,16,0,1142,1143,6, + 125,11,0,1143,266,1,0,0,0,1144,1145,3,167,76,0,1145,1146,1,0,0,0,1146,1147, + 6,126,14,0,1147,1148,6,126,26,0,1148,268,1,0,0,0,1149,1150,7,7,0,0,1150, + 1151,7,9,0,0,1151,1152,1,0,0,0,1152,1153,6,127,27,0,1153,270,1,0,0,0,1154, + 1155,7,19,0,0,1155,1156,7,1,0,0,1156,1157,7,5,0,0,1157,1158,7,10,0,0,1158, + 1159,1,0,0,0,1159,1160,6,128,27,0,1160,272,1,0,0,0,1161,1162,8,34,0,0,1162, + 274,1,0,0,0,1163,1165,3,273,129,0,1164,1163,1,0,0,0,1165,1166,1,0,0,0,1166, + 1164,1,0,0,0,1166,1167,1,0,0,0,1167,1168,1,0,0,0,1168,1169,3,61,23,0,1169, + 1171,1,0,0,0,1170,1164,1,0,0,0,1170,1171,1,0,0,0,1171,1173,1,0,0,0,1172, + 1174,3,273,129,0,1173,1172,1,0,0,0,1174,1175,1,0,0,0,1175,1173,1,0,0,0, + 1175,1176,1,0,0,0,1176,276,1,0,0,0,1177,1178,3,275,130,0,1178,1179,1,0, + 0,0,1179,1180,6,131,28,0,1180,278,1,0,0,0,1181,1182,3,55,20,0,1182,1183, + 1,0,0,0,1183,1184,6,132,10,0,1184,280,1,0,0,0,1185,1186,3,57,21,0,1186, + 1187,1,0,0,0,1187,1188,6,133,10,0,1188,282,1,0,0,0,1189,1190,3,59,22,0, + 1190,1191,1,0,0,0,1191,1192,6,134,10,0,1192,284,1,0,0,0,1193,1194,3,63, + 24,0,1194,1195,1,0,0,0,1195,1196,6,135,16,0,1196,1197,6,135,11,0,1197,1198, + 6,135,11,0,1198,286,1,0,0,0,1199,1200,3,97,41,0,1200,1201,1,0,0,0,1201, + 1202,6,136,19,0,1202,288,1,0,0,0,1203,1204,3,101,43,0,1204,1205,1,0,0,0, + 1205,1206,6,137,18,0,1206,290,1,0,0,0,1207,1208,3,105,45,0,1208,1209,1, + 0,0,0,1209,1210,6,138,22,0,1210,292,1,0,0,0,1211,1212,3,271,128,0,1212, + 1213,1,0,0,0,1213,1214,6,139,29,0,1214,294,1,0,0,0,1215,1216,3,235,110, + 0,1216,1217,1,0,0,0,1217,1218,6,140,25,0,1218,296,1,0,0,0,1219,1220,3,175, + 80,0,1220,1221,1,0,0,0,1221,1222,6,141,30,0,1222,298,1,0,0,0,1223,1224, + 4,142,8,0,1224,1225,3,129,57,0,1225,1226,1,0,0,0,1226,1227,6,142,23,0,1227, + 300,1,0,0,0,1228,1229,4,143,9,0,1229,1230,3,165,75,0,1230,1231,1,0,0,0, + 1231,1232,6,143,24,0,1232,302,1,0,0,0,1233,1234,3,55,20,0,1234,1235,1,0, + 0,0,1235,1236,6,144,10,0,1236,304,1,0,0,0,1237,1238,3,57,21,0,1238,1239, + 1,0,0,0,1239,1240,6,145,10,0,1240,306,1,0,0,0,1241,1242,3,59,22,0,1242, + 1243,1,0,0,0,1243,1244,6,146,10,0,1244,308,1,0,0,0,1245,1246,3,63,24,0, + 1246,1247,1,0,0,0,1247,1248,6,147,16,0,1248,1249,6,147,11,0,1249,310,1, + 0,0,0,1250,1251,3,105,45,0,1251,1252,1,0,0,0,1252,1253,6,148,22,0,1253, + 312,1,0,0,0,1254,1255,4,149,10,0,1255,1256,3,129,57,0,1256,1257,1,0,0,0, + 1257,1258,6,149,23,0,1258,314,1,0,0,0,1259,1260,4,150,11,0,1260,1261,3, + 165,75,0,1261,1262,1,0,0,0,1262,1263,6,150,24,0,1263,316,1,0,0,0,1264,1265, + 3,175,80,0,1265,1266,1,0,0,0,1266,1267,6,151,30,0,1267,318,1,0,0,0,1268, + 1269,3,171,78,0,1269,1270,1,0,0,0,1270,1271,6,152,31,0,1271,320,1,0,0,0, + 1272,1273,3,55,20,0,1273,1274,1,0,0,0,1274,1275,6,153,10,0,1275,322,1,0, + 0,0,1276,1277,3,57,21,0,1277,1278,1,0,0,0,1278,1279,6,154,10,0,1279,324, + 1,0,0,0,1280,1281,3,59,22,0,1281,1282,1,0,0,0,1282,1283,6,155,10,0,1283, + 326,1,0,0,0,1284,1285,3,63,24,0,1285,1286,1,0,0,0,1286,1287,6,156,16,0, + 1287,1288,6,156,11,0,1288,328,1,0,0,0,1289,1290,7,1,0,0,1290,1291,7,9,0, + 0,1291,1292,7,15,0,0,1292,1293,7,7,0,0,1293,330,1,0,0,0,1294,1295,3,55, + 20,0,1295,1296,1,0,0,0,1296,1297,6,158,10,0,1297,332,1,0,0,0,1298,1299, + 3,57,21,0,1299,1300,1,0,0,0,1300,1301,6,159,10,0,1301,334,1,0,0,0,1302, + 1303,3,59,22,0,1303,1304,1,0,0,0,1304,1305,6,160,10,0,1305,336,1,0,0,0, + 1306,1307,3,169,77,0,1307,1308,1,0,0,0,1308,1309,6,161,17,0,1309,1310,6, + 161,11,0,1310,338,1,0,0,0,1311,1312,3,61,23,0,1312,1313,1,0,0,0,1313,1314, + 6,162,12,0,1314,340,1,0,0,0,1315,1321,3,75,30,0,1316,1321,3,65,25,0,1317, + 1321,3,105,45,0,1318,1321,3,67,26,0,1319,1321,3,81,33,0,1320,1315,1,0,0, + 0,1320,1316,1,0,0,0,1320,1317,1,0,0,0,1320,1318,1,0,0,0,1320,1319,1,0,0, + 0,1321,1322,1,0,0,0,1322,1320,1,0,0,0,1322,1323,1,0,0,0,1323,342,1,0,0, + 0,1324,1325,3,55,20,0,1325,1326,1,0,0,0,1326,1327,6,164,10,0,1327,344,1, + 0,0,0,1328,1329,3,57,21,0,1329,1330,1,0,0,0,1330,1331,6,165,10,0,1331,346, + 1,0,0,0,1332,1333,3,59,22,0,1333,1334,1,0,0,0,1334,1335,6,166,10,0,1335, + 348,1,0,0,0,1336,1337,3,63,24,0,1337,1338,1,0,0,0,1338,1339,6,167,16,0, + 1339,1340,6,167,11,0,1340,350,1,0,0,0,1341,1342,3,61,23,0,1342,1343,1,0, + 0,0,1343,1344,6,168,12,0,1344,352,1,0,0,0,1345,1346,3,101,43,0,1346,1347, + 1,0,0,0,1347,1348,6,169,18,0,1348,354,1,0,0,0,1349,1350,3,105,45,0,1350, + 1351,1,0,0,0,1351,1352,6,170,22,0,1352,356,1,0,0,0,1353,1354,3,269,127, + 0,1354,1355,1,0,0,0,1355,1356,6,171,32,0,1356,1357,6,171,33,0,1357,358, + 1,0,0,0,1358,1359,3,209,97,0,1359,1360,1,0,0,0,1360,1361,6,172,20,0,1361, + 360,1,0,0,0,1362,1363,3,85,35,0,1363,1364,1,0,0,0,1364,1365,6,173,21,0, + 1365,362,1,0,0,0,1366,1367,3,55,20,0,1367,1368,1,0,0,0,1368,1369,6,174, + 10,0,1369,364,1,0,0,0,1370,1371,3,57,21,0,1371,1372,1,0,0,0,1372,1373,6, + 175,10,0,1373,366,1,0,0,0,1374,1375,3,59,22,0,1375,1376,1,0,0,0,1376,1377, + 6,176,10,0,1377,368,1,0,0,0,1378,1379,3,63,24,0,1379,1380,1,0,0,0,1380, + 1381,6,177,16,0,1381,1382,6,177,11,0,1382,1383,6,177,11,0,1383,370,1,0, + 0,0,1384,1385,3,101,43,0,1385,1386,1,0,0,0,1386,1387,6,178,18,0,1387,372, + 1,0,0,0,1388,1389,3,105,45,0,1389,1390,1,0,0,0,1390,1391,6,179,22,0,1391, + 374,1,0,0,0,1392,1393,3,235,110,0,1393,1394,1,0,0,0,1394,1395,6,180,25, + 0,1395,376,1,0,0,0,1396,1397,3,55,20,0,1397,1398,1,0,0,0,1398,1399,6,181, + 10,0,1399,378,1,0,0,0,1400,1401,3,57,21,0,1401,1402,1,0,0,0,1402,1403,6, + 182,10,0,1403,380,1,0,0,0,1404,1405,3,59,22,0,1405,1406,1,0,0,0,1406,1407, + 6,183,10,0,1407,382,1,0,0,0,1408,1409,3,63,24,0,1409,1410,1,0,0,0,1410, + 1411,6,184,16,0,1411,1412,6,184,11,0,1412,384,1,0,0,0,1413,1414,3,209,97, + 0,1414,1415,1,0,0,0,1415,1416,6,185,20,0,1416,1417,6,185,11,0,1417,1418, + 6,185,34,0,1418,386,1,0,0,0,1419,1420,3,85,35,0,1420,1421,1,0,0,0,1421, + 1422,6,186,21,0,1422,1423,6,186,11,0,1423,1424,6,186,34,0,1424,388,1,0, + 0,0,1425,1426,3,55,20,0,1426,1427,1,0,0,0,1427,1428,6,187,10,0,1428,390, + 1,0,0,0,1429,1430,3,57,21,0,1430,1431,1,0,0,0,1431,1432,6,188,10,0,1432, + 392,1,0,0,0,1433,1434,3,59,22,0,1434,1435,1,0,0,0,1435,1436,6,189,10,0, + 1436,394,1,0,0,0,1437,1438,3,61,23,0,1438,1439,1,0,0,0,1439,1440,6,190, + 12,0,1440,1441,6,190,11,0,1441,1442,6,190,9,0,1442,396,1,0,0,0,1443,1444, + 3,101,43,0,1444,1445,1,0,0,0,1445,1446,6,191,18,0,1446,1447,6,191,11,0, + 1447,1448,6,191,9,0,1448,398,1,0,0,0,1449,1450,3,55,20,0,1450,1451,1,0, + 0,0,1451,1452,6,192,10,0,1452,400,1,0,0,0,1453,1454,3,57,21,0,1454,1455, + 1,0,0,0,1455,1456,6,193,10,0,1456,402,1,0,0,0,1457,1458,3,59,22,0,1458, + 1459,1,0,0,0,1459,1460,6,194,10,0,1460,404,1,0,0,0,1461,1462,3,175,80,0, + 1462,1463,1,0,0,0,1463,1464,6,195,11,0,1464,1465,6,195,0,0,1465,1466,6, + 195,30,0,1466,406,1,0,0,0,1467,1468,3,171,78,0,1468,1469,1,0,0,0,1469,1470, + 6,196,11,0,1470,1471,6,196,0,0,1471,1472,6,196,31,0,1472,408,1,0,0,0,1473, + 1474,3,91,38,0,1474,1475,1,0,0,0,1475,1476,6,197,11,0,1476,1477,6,197,0, + 0,1477,1478,6,197,35,0,1478,410,1,0,0,0,1479,1480,3,63,24,0,1480,1481,1, + 0,0,0,1481,1482,6,198,16,0,1482,1483,6,198,11,0,1483,412,1,0,0,0,65,0,1, + 2,3,4,5,6,7,8,9,10,11,12,13,14,581,591,595,598,607,609,620,641,646,655, + 662,667,669,680,688,691,693,698,703,709,716,721,727,730,738,742,873,878, + 885,887,903,908,913,915,921,998,1003,1052,1056,1061,1066,1071,1073,1077, + 1079,1166,1170,1175,1320,1322,36,5,1,0,5,4,0,5,6,0,5,2,0,5,3,0,5,8,0,5, + 5,0,5,9,0,5,11,0,5,13,0,0,1,0,4,0,0,7,24,0,7,16,0,7,65,0,5,0,0,7,25,0,7, + 66,0,7,34,0,7,32,0,7,76,0,7,26,0,7,36,0,7,48,0,7,64,0,7,80,0,5,10,0,5,7, + 0,7,90,0,7,89,0,7,68,0,7,67,0,7,88,0,5,12,0,5,14,0,7,29,0]; private static __ATN: ATN; public static get _ATN(): ATN { diff --git a/packages/kbn-esql-ast/src/antlr/esql_parser.g4 b/packages/kbn-esql-ast/src/antlr/esql_parser.g4 index 261b4f712b5b..6a76e32d28f3 100644 --- a/packages/kbn-esql-ast/src/antlr/esql_parser.g4 +++ b/packages/kbn-esql-ast/src/antlr/esql_parser.g4 @@ -79,7 +79,7 @@ regexBooleanExpression ; matchBooleanExpression - : valueExpression MATCH queryString=string + : fieldExp=qualifiedName COLON queryString=constant ; valueExpression @@ -107,9 +107,7 @@ functionExpression ; functionName - // Additional function identifiers that are already a reserved word in the language - : MATCH - | identifierOrParameter + : identifierOrParameter ; dataType diff --git a/packages/kbn-esql-ast/src/antlr/esql_parser.interp b/packages/kbn-esql-ast/src/antlr/esql_parser.interp index b52d842e79fb..a2b339f378f1 100644 --- a/packages/kbn-esql-ast/src/antlr/esql_parser.interp +++ b/packages/kbn-esql-ast/src/antlr/esql_parser.interp @@ -23,6 +23,7 @@ null null null null +':' '|' null null @@ -62,7 +63,6 @@ null '*' '/' '%' -'match' null null ']' @@ -103,7 +103,6 @@ null null null null -':' null null null @@ -146,6 +145,7 @@ UNKNOWN_CMD LINE_COMMENT MULTILINE_COMMENT WS +COLON PIPE QUOTED_STRING INTEGER_LITERAL @@ -185,7 +185,6 @@ MINUS ASTERISK SLASH PERCENT -MATCH NAMED_OR_POSITIONAL_PARAM OPENING_BRACKET CLOSING_BRACKET @@ -226,7 +225,6 @@ INFO SHOW_LINE_COMMENT SHOW_MULTILINE_COMMENT SHOW_WS -COLON SETTING SETTING_LINE_COMMENT SETTTING_MULTILINE_COMMENT @@ -310,4 +308,4 @@ inlinestatsCommand atn: -[4, 1, 120, 605, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 134, 8, 1, 10, 1, 12, 1, 137, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 145, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 163, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 175, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 182, 8, 5, 10, 5, 12, 5, 185, 9, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 192, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 198, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 206, 8, 5, 10, 5, 12, 5, 209, 9, 5, 1, 6, 1, 6, 3, 6, 213, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 220, 8, 6, 1, 6, 1, 6, 1, 6, 3, 6, 225, 8, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 236, 8, 8, 1, 9, 1, 9, 1, 9, 1, 9, 3, 9, 242, 8, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 5, 9, 250, 8, 9, 10, 9, 12, 9, 253, 9, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 263, 8, 10, 1, 10, 1, 10, 1, 10, 5, 10, 268, 8, 10, 10, 10, 12, 10, 271, 9, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 279, 8, 11, 10, 11, 12, 11, 282, 9, 11, 3, 11, 284, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 3, 12, 290, 8, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 5, 15, 300, 8, 15, 10, 15, 12, 15, 303, 9, 15, 1, 16, 1, 16, 1, 16, 3, 16, 308, 8, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 5, 17, 316, 8, 17, 10, 17, 12, 17, 319, 9, 17, 1, 17, 3, 17, 322, 8, 17, 1, 18, 1, 18, 1, 18, 3, 18, 327, 8, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 21, 1, 21, 3, 21, 337, 8, 21, 1, 22, 1, 22, 1, 22, 1, 22, 5, 22, 343, 8, 22, 10, 22, 12, 22, 346, 9, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 356, 8, 24, 10, 24, 12, 24, 359, 9, 24, 1, 24, 3, 24, 362, 8, 24, 1, 24, 1, 24, 3, 24, 366, 8, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 3, 26, 373, 8, 26, 1, 26, 1, 26, 3, 26, 377, 8, 26, 1, 27, 1, 27, 1, 27, 5, 27, 382, 8, 27, 10, 27, 12, 27, 385, 9, 27, 1, 28, 1, 28, 1, 28, 3, 28, 390, 8, 28, 1, 29, 1, 29, 1, 29, 5, 29, 395, 8, 29, 10, 29, 12, 29, 398, 9, 29, 1, 30, 1, 30, 1, 30, 5, 30, 403, 8, 30, 10, 30, 12, 30, 406, 9, 30, 1, 31, 1, 31, 1, 31, 5, 31, 411, 8, 31, 10, 31, 12, 31, 414, 9, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 3, 33, 421, 8, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 436, 8, 34, 10, 34, 12, 34, 439, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 447, 8, 34, 10, 34, 12, 34, 450, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 458, 8, 34, 10, 34, 12, 34, 461, 9, 34, 1, 34, 1, 34, 3, 34, 465, 8, 34, 1, 35, 1, 35, 3, 35, 469, 8, 35, 1, 36, 1, 36, 1, 36, 3, 36, 474, 8, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 483, 8, 38, 10, 38, 12, 38, 486, 9, 38, 1, 39, 1, 39, 3, 39, 490, 8, 39, 1, 39, 1, 39, 3, 39, 494, 8, 39, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 5, 42, 506, 8, 42, 10, 42, 12, 42, 509, 9, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 3, 44, 519, 8, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 5, 47, 531, 8, 47, 10, 47, 12, 47, 534, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 50, 1, 50, 3, 50, 544, 8, 50, 1, 51, 3, 51, 547, 8, 51, 1, 51, 1, 51, 1, 52, 3, 52, 552, 8, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 574, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 5, 58, 580, 8, 58, 10, 58, 12, 58, 583, 9, 58, 3, 58, 585, 8, 58, 1, 59, 1, 59, 1, 59, 3, 59, 590, 8, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 3, 61, 603, 8, 61, 1, 61, 0, 4, 2, 10, 18, 20, 62, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 0, 8, 1, 0, 58, 59, 1, 0, 60, 62, 2, 0, 25, 25, 76, 76, 1, 0, 67, 68, 2, 0, 30, 30, 34, 34, 2, 0, 37, 37, 40, 40, 2, 0, 36, 36, 50, 50, 2, 0, 51, 51, 53, 57, 631, 0, 124, 1, 0, 0, 0, 2, 127, 1, 0, 0, 0, 4, 144, 1, 0, 0, 0, 6, 162, 1, 0, 0, 0, 8, 164, 1, 0, 0, 0, 10, 197, 1, 0, 0, 0, 12, 224, 1, 0, 0, 0, 14, 226, 1, 0, 0, 0, 16, 235, 1, 0, 0, 0, 18, 241, 1, 0, 0, 0, 20, 262, 1, 0, 0, 0, 22, 272, 1, 0, 0, 0, 24, 289, 1, 0, 0, 0, 26, 291, 1, 0, 0, 0, 28, 293, 1, 0, 0, 0, 30, 296, 1, 0, 0, 0, 32, 307, 1, 0, 0, 0, 34, 311, 1, 0, 0, 0, 36, 326, 1, 0, 0, 0, 38, 330, 1, 0, 0, 0, 40, 332, 1, 0, 0, 0, 42, 336, 1, 0, 0, 0, 44, 338, 1, 0, 0, 0, 46, 347, 1, 0, 0, 0, 48, 351, 1, 0, 0, 0, 50, 367, 1, 0, 0, 0, 52, 370, 1, 0, 0, 0, 54, 378, 1, 0, 0, 0, 56, 386, 1, 0, 0, 0, 58, 391, 1, 0, 0, 0, 60, 399, 1, 0, 0, 0, 62, 407, 1, 0, 0, 0, 64, 415, 1, 0, 0, 0, 66, 420, 1, 0, 0, 0, 68, 464, 1, 0, 0, 0, 70, 468, 1, 0, 0, 0, 72, 473, 1, 0, 0, 0, 74, 475, 1, 0, 0, 0, 76, 478, 1, 0, 0, 0, 78, 487, 1, 0, 0, 0, 80, 495, 1, 0, 0, 0, 82, 498, 1, 0, 0, 0, 84, 501, 1, 0, 0, 0, 86, 510, 1, 0, 0, 0, 88, 514, 1, 0, 0, 0, 90, 520, 1, 0, 0, 0, 92, 524, 1, 0, 0, 0, 94, 527, 1, 0, 0, 0, 96, 535, 1, 0, 0, 0, 98, 539, 1, 0, 0, 0, 100, 543, 1, 0, 0, 0, 102, 546, 1, 0, 0, 0, 104, 551, 1, 0, 0, 0, 106, 555, 1, 0, 0, 0, 108, 557, 1, 0, 0, 0, 110, 559, 1, 0, 0, 0, 112, 562, 1, 0, 0, 0, 114, 566, 1, 0, 0, 0, 116, 569, 1, 0, 0, 0, 118, 589, 1, 0, 0, 0, 120, 593, 1, 0, 0, 0, 122, 598, 1, 0, 0, 0, 124, 125, 3, 2, 1, 0, 125, 126, 5, 0, 0, 1, 126, 1, 1, 0, 0, 0, 127, 128, 6, 1, -1, 0, 128, 129, 3, 4, 2, 0, 129, 135, 1, 0, 0, 0, 130, 131, 10, 1, 0, 0, 131, 132, 5, 24, 0, 0, 132, 134, 3, 6, 3, 0, 133, 130, 1, 0, 0, 0, 134, 137, 1, 0, 0, 0, 135, 133, 1, 0, 0, 0, 135, 136, 1, 0, 0, 0, 136, 3, 1, 0, 0, 0, 137, 135, 1, 0, 0, 0, 138, 145, 3, 110, 55, 0, 139, 145, 3, 34, 17, 0, 140, 145, 3, 28, 14, 0, 141, 145, 3, 114, 57, 0, 142, 143, 4, 2, 1, 0, 143, 145, 3, 48, 24, 0, 144, 138, 1, 0, 0, 0, 144, 139, 1, 0, 0, 0, 144, 140, 1, 0, 0, 0, 144, 141, 1, 0, 0, 0, 144, 142, 1, 0, 0, 0, 145, 5, 1, 0, 0, 0, 146, 163, 3, 50, 25, 0, 147, 163, 3, 8, 4, 0, 148, 163, 3, 80, 40, 0, 149, 163, 3, 74, 37, 0, 150, 163, 3, 52, 26, 0, 151, 163, 3, 76, 38, 0, 152, 163, 3, 82, 41, 0, 153, 163, 3, 84, 42, 0, 154, 163, 3, 88, 44, 0, 155, 163, 3, 90, 45, 0, 156, 163, 3, 116, 58, 0, 157, 163, 3, 92, 46, 0, 158, 159, 4, 3, 2, 0, 159, 163, 3, 122, 61, 0, 160, 161, 4, 3, 3, 0, 161, 163, 3, 120, 60, 0, 162, 146, 1, 0, 0, 0, 162, 147, 1, 0, 0, 0, 162, 148, 1, 0, 0, 0, 162, 149, 1, 0, 0, 0, 162, 150, 1, 0, 0, 0, 162, 151, 1, 0, 0, 0, 162, 152, 1, 0, 0, 0, 162, 153, 1, 0, 0, 0, 162, 154, 1, 0, 0, 0, 162, 155, 1, 0, 0, 0, 162, 156, 1, 0, 0, 0, 162, 157, 1, 0, 0, 0, 162, 158, 1, 0, 0, 0, 162, 160, 1, 0, 0, 0, 163, 7, 1, 0, 0, 0, 164, 165, 5, 16, 0, 0, 165, 166, 3, 10, 5, 0, 166, 9, 1, 0, 0, 0, 167, 168, 6, 5, -1, 0, 168, 169, 5, 43, 0, 0, 169, 198, 3, 10, 5, 8, 170, 198, 3, 16, 8, 0, 171, 198, 3, 12, 6, 0, 172, 174, 3, 16, 8, 0, 173, 175, 5, 43, 0, 0, 174, 173, 1, 0, 0, 0, 174, 175, 1, 0, 0, 0, 175, 176, 1, 0, 0, 0, 176, 177, 5, 38, 0, 0, 177, 178, 5, 42, 0, 0, 178, 183, 3, 16, 8, 0, 179, 180, 5, 33, 0, 0, 180, 182, 3, 16, 8, 0, 181, 179, 1, 0, 0, 0, 182, 185, 1, 0, 0, 0, 183, 181, 1, 0, 0, 0, 183, 184, 1, 0, 0, 0, 184, 186, 1, 0, 0, 0, 185, 183, 1, 0, 0, 0, 186, 187, 5, 49, 0, 0, 187, 198, 1, 0, 0, 0, 188, 189, 3, 16, 8, 0, 189, 191, 5, 39, 0, 0, 190, 192, 5, 43, 0, 0, 191, 190, 1, 0, 0, 0, 191, 192, 1, 0, 0, 0, 192, 193, 1, 0, 0, 0, 193, 194, 5, 44, 0, 0, 194, 198, 1, 0, 0, 0, 195, 196, 4, 5, 4, 0, 196, 198, 3, 14, 7, 0, 197, 167, 1, 0, 0, 0, 197, 170, 1, 0, 0, 0, 197, 171, 1, 0, 0, 0, 197, 172, 1, 0, 0, 0, 197, 188, 1, 0, 0, 0, 197, 195, 1, 0, 0, 0, 198, 207, 1, 0, 0, 0, 199, 200, 10, 5, 0, 0, 200, 201, 5, 29, 0, 0, 201, 206, 3, 10, 5, 6, 202, 203, 10, 4, 0, 0, 203, 204, 5, 46, 0, 0, 204, 206, 3, 10, 5, 5, 205, 199, 1, 0, 0, 0, 205, 202, 1, 0, 0, 0, 206, 209, 1, 0, 0, 0, 207, 205, 1, 0, 0, 0, 207, 208, 1, 0, 0, 0, 208, 11, 1, 0, 0, 0, 209, 207, 1, 0, 0, 0, 210, 212, 3, 16, 8, 0, 211, 213, 5, 43, 0, 0, 212, 211, 1, 0, 0, 0, 212, 213, 1, 0, 0, 0, 213, 214, 1, 0, 0, 0, 214, 215, 5, 41, 0, 0, 215, 216, 3, 106, 53, 0, 216, 225, 1, 0, 0, 0, 217, 219, 3, 16, 8, 0, 218, 220, 5, 43, 0, 0, 219, 218, 1, 0, 0, 0, 219, 220, 1, 0, 0, 0, 220, 221, 1, 0, 0, 0, 221, 222, 5, 48, 0, 0, 222, 223, 3, 106, 53, 0, 223, 225, 1, 0, 0, 0, 224, 210, 1, 0, 0, 0, 224, 217, 1, 0, 0, 0, 225, 13, 1, 0, 0, 0, 226, 227, 3, 16, 8, 0, 227, 228, 5, 63, 0, 0, 228, 229, 3, 106, 53, 0, 229, 15, 1, 0, 0, 0, 230, 236, 3, 18, 9, 0, 231, 232, 3, 18, 9, 0, 232, 233, 3, 108, 54, 0, 233, 234, 3, 18, 9, 0, 234, 236, 1, 0, 0, 0, 235, 230, 1, 0, 0, 0, 235, 231, 1, 0, 0, 0, 236, 17, 1, 0, 0, 0, 237, 238, 6, 9, -1, 0, 238, 242, 3, 20, 10, 0, 239, 240, 7, 0, 0, 0, 240, 242, 3, 18, 9, 3, 241, 237, 1, 0, 0, 0, 241, 239, 1, 0, 0, 0, 242, 251, 1, 0, 0, 0, 243, 244, 10, 2, 0, 0, 244, 245, 7, 1, 0, 0, 245, 250, 3, 18, 9, 3, 246, 247, 10, 1, 0, 0, 247, 248, 7, 0, 0, 0, 248, 250, 3, 18, 9, 2, 249, 243, 1, 0, 0, 0, 249, 246, 1, 0, 0, 0, 250, 253, 1, 0, 0, 0, 251, 249, 1, 0, 0, 0, 251, 252, 1, 0, 0, 0, 252, 19, 1, 0, 0, 0, 253, 251, 1, 0, 0, 0, 254, 255, 6, 10, -1, 0, 255, 263, 3, 68, 34, 0, 256, 263, 3, 58, 29, 0, 257, 263, 3, 22, 11, 0, 258, 259, 5, 42, 0, 0, 259, 260, 3, 10, 5, 0, 260, 261, 5, 49, 0, 0, 261, 263, 1, 0, 0, 0, 262, 254, 1, 0, 0, 0, 262, 256, 1, 0, 0, 0, 262, 257, 1, 0, 0, 0, 262, 258, 1, 0, 0, 0, 263, 269, 1, 0, 0, 0, 264, 265, 10, 1, 0, 0, 265, 266, 5, 32, 0, 0, 266, 268, 3, 26, 13, 0, 267, 264, 1, 0, 0, 0, 268, 271, 1, 0, 0, 0, 269, 267, 1, 0, 0, 0, 269, 270, 1, 0, 0, 0, 270, 21, 1, 0, 0, 0, 271, 269, 1, 0, 0, 0, 272, 273, 3, 24, 12, 0, 273, 283, 5, 42, 0, 0, 274, 284, 5, 60, 0, 0, 275, 280, 3, 10, 5, 0, 276, 277, 5, 33, 0, 0, 277, 279, 3, 10, 5, 0, 278, 276, 1, 0, 0, 0, 279, 282, 1, 0, 0, 0, 280, 278, 1, 0, 0, 0, 280, 281, 1, 0, 0, 0, 281, 284, 1, 0, 0, 0, 282, 280, 1, 0, 0, 0, 283, 274, 1, 0, 0, 0, 283, 275, 1, 0, 0, 0, 283, 284, 1, 0, 0, 0, 284, 285, 1, 0, 0, 0, 285, 286, 5, 49, 0, 0, 286, 23, 1, 0, 0, 0, 287, 290, 5, 63, 0, 0, 288, 290, 3, 72, 36, 0, 289, 287, 1, 0, 0, 0, 289, 288, 1, 0, 0, 0, 290, 25, 1, 0, 0, 0, 291, 292, 3, 64, 32, 0, 292, 27, 1, 0, 0, 0, 293, 294, 5, 12, 0, 0, 294, 295, 3, 30, 15, 0, 295, 29, 1, 0, 0, 0, 296, 301, 3, 32, 16, 0, 297, 298, 5, 33, 0, 0, 298, 300, 3, 32, 16, 0, 299, 297, 1, 0, 0, 0, 300, 303, 1, 0, 0, 0, 301, 299, 1, 0, 0, 0, 301, 302, 1, 0, 0, 0, 302, 31, 1, 0, 0, 0, 303, 301, 1, 0, 0, 0, 304, 305, 3, 58, 29, 0, 305, 306, 5, 31, 0, 0, 306, 308, 1, 0, 0, 0, 307, 304, 1, 0, 0, 0, 307, 308, 1, 0, 0, 0, 308, 309, 1, 0, 0, 0, 309, 310, 3, 10, 5, 0, 310, 33, 1, 0, 0, 0, 311, 312, 5, 6, 0, 0, 312, 317, 3, 36, 18, 0, 313, 314, 5, 33, 0, 0, 314, 316, 3, 36, 18, 0, 315, 313, 1, 0, 0, 0, 316, 319, 1, 0, 0, 0, 317, 315, 1, 0, 0, 0, 317, 318, 1, 0, 0, 0, 318, 321, 1, 0, 0, 0, 319, 317, 1, 0, 0, 0, 320, 322, 3, 42, 21, 0, 321, 320, 1, 0, 0, 0, 321, 322, 1, 0, 0, 0, 322, 35, 1, 0, 0, 0, 323, 324, 3, 38, 19, 0, 324, 325, 5, 104, 0, 0, 325, 327, 1, 0, 0, 0, 326, 323, 1, 0, 0, 0, 326, 327, 1, 0, 0, 0, 327, 328, 1, 0, 0, 0, 328, 329, 3, 40, 20, 0, 329, 37, 1, 0, 0, 0, 330, 331, 5, 76, 0, 0, 331, 39, 1, 0, 0, 0, 332, 333, 7, 2, 0, 0, 333, 41, 1, 0, 0, 0, 334, 337, 3, 44, 22, 0, 335, 337, 3, 46, 23, 0, 336, 334, 1, 0, 0, 0, 336, 335, 1, 0, 0, 0, 337, 43, 1, 0, 0, 0, 338, 339, 5, 75, 0, 0, 339, 344, 5, 76, 0, 0, 340, 341, 5, 33, 0, 0, 341, 343, 5, 76, 0, 0, 342, 340, 1, 0, 0, 0, 343, 346, 1, 0, 0, 0, 344, 342, 1, 0, 0, 0, 344, 345, 1, 0, 0, 0, 345, 45, 1, 0, 0, 0, 346, 344, 1, 0, 0, 0, 347, 348, 5, 65, 0, 0, 348, 349, 3, 44, 22, 0, 349, 350, 5, 66, 0, 0, 350, 47, 1, 0, 0, 0, 351, 352, 5, 19, 0, 0, 352, 357, 3, 36, 18, 0, 353, 354, 5, 33, 0, 0, 354, 356, 3, 36, 18, 0, 355, 353, 1, 0, 0, 0, 356, 359, 1, 0, 0, 0, 357, 355, 1, 0, 0, 0, 357, 358, 1, 0, 0, 0, 358, 361, 1, 0, 0, 0, 359, 357, 1, 0, 0, 0, 360, 362, 3, 54, 27, 0, 361, 360, 1, 0, 0, 0, 361, 362, 1, 0, 0, 0, 362, 365, 1, 0, 0, 0, 363, 364, 5, 28, 0, 0, 364, 366, 3, 30, 15, 0, 365, 363, 1, 0, 0, 0, 365, 366, 1, 0, 0, 0, 366, 49, 1, 0, 0, 0, 367, 368, 5, 4, 0, 0, 368, 369, 3, 30, 15, 0, 369, 51, 1, 0, 0, 0, 370, 372, 5, 15, 0, 0, 371, 373, 3, 54, 27, 0, 372, 371, 1, 0, 0, 0, 372, 373, 1, 0, 0, 0, 373, 376, 1, 0, 0, 0, 374, 375, 5, 28, 0, 0, 375, 377, 3, 30, 15, 0, 376, 374, 1, 0, 0, 0, 376, 377, 1, 0, 0, 0, 377, 53, 1, 0, 0, 0, 378, 383, 3, 56, 28, 0, 379, 380, 5, 33, 0, 0, 380, 382, 3, 56, 28, 0, 381, 379, 1, 0, 0, 0, 382, 385, 1, 0, 0, 0, 383, 381, 1, 0, 0, 0, 383, 384, 1, 0, 0, 0, 384, 55, 1, 0, 0, 0, 385, 383, 1, 0, 0, 0, 386, 389, 3, 32, 16, 0, 387, 388, 5, 16, 0, 0, 388, 390, 3, 10, 5, 0, 389, 387, 1, 0, 0, 0, 389, 390, 1, 0, 0, 0, 390, 57, 1, 0, 0, 0, 391, 396, 3, 72, 36, 0, 392, 393, 5, 35, 0, 0, 393, 395, 3, 72, 36, 0, 394, 392, 1, 0, 0, 0, 395, 398, 1, 0, 0, 0, 396, 394, 1, 0, 0, 0, 396, 397, 1, 0, 0, 0, 397, 59, 1, 0, 0, 0, 398, 396, 1, 0, 0, 0, 399, 404, 3, 66, 33, 0, 400, 401, 5, 35, 0, 0, 401, 403, 3, 66, 33, 0, 402, 400, 1, 0, 0, 0, 403, 406, 1, 0, 0, 0, 404, 402, 1, 0, 0, 0, 404, 405, 1, 0, 0, 0, 405, 61, 1, 0, 0, 0, 406, 404, 1, 0, 0, 0, 407, 412, 3, 60, 30, 0, 408, 409, 5, 33, 0, 0, 409, 411, 3, 60, 30, 0, 410, 408, 1, 0, 0, 0, 411, 414, 1, 0, 0, 0, 412, 410, 1, 0, 0, 0, 412, 413, 1, 0, 0, 0, 413, 63, 1, 0, 0, 0, 414, 412, 1, 0, 0, 0, 415, 416, 7, 3, 0, 0, 416, 65, 1, 0, 0, 0, 417, 421, 5, 80, 0, 0, 418, 419, 4, 33, 10, 0, 419, 421, 3, 70, 35, 0, 420, 417, 1, 0, 0, 0, 420, 418, 1, 0, 0, 0, 421, 67, 1, 0, 0, 0, 422, 465, 5, 44, 0, 0, 423, 424, 3, 104, 52, 0, 424, 425, 5, 67, 0, 0, 425, 465, 1, 0, 0, 0, 426, 465, 3, 102, 51, 0, 427, 465, 3, 104, 52, 0, 428, 465, 3, 98, 49, 0, 429, 465, 3, 70, 35, 0, 430, 465, 3, 106, 53, 0, 431, 432, 5, 65, 0, 0, 432, 437, 3, 100, 50, 0, 433, 434, 5, 33, 0, 0, 434, 436, 3, 100, 50, 0, 435, 433, 1, 0, 0, 0, 436, 439, 1, 0, 0, 0, 437, 435, 1, 0, 0, 0, 437, 438, 1, 0, 0, 0, 438, 440, 1, 0, 0, 0, 439, 437, 1, 0, 0, 0, 440, 441, 5, 66, 0, 0, 441, 465, 1, 0, 0, 0, 442, 443, 5, 65, 0, 0, 443, 448, 3, 98, 49, 0, 444, 445, 5, 33, 0, 0, 445, 447, 3, 98, 49, 0, 446, 444, 1, 0, 0, 0, 447, 450, 1, 0, 0, 0, 448, 446, 1, 0, 0, 0, 448, 449, 1, 0, 0, 0, 449, 451, 1, 0, 0, 0, 450, 448, 1, 0, 0, 0, 451, 452, 5, 66, 0, 0, 452, 465, 1, 0, 0, 0, 453, 454, 5, 65, 0, 0, 454, 459, 3, 106, 53, 0, 455, 456, 5, 33, 0, 0, 456, 458, 3, 106, 53, 0, 457, 455, 1, 0, 0, 0, 458, 461, 1, 0, 0, 0, 459, 457, 1, 0, 0, 0, 459, 460, 1, 0, 0, 0, 460, 462, 1, 0, 0, 0, 461, 459, 1, 0, 0, 0, 462, 463, 5, 66, 0, 0, 463, 465, 1, 0, 0, 0, 464, 422, 1, 0, 0, 0, 464, 423, 1, 0, 0, 0, 464, 426, 1, 0, 0, 0, 464, 427, 1, 0, 0, 0, 464, 428, 1, 0, 0, 0, 464, 429, 1, 0, 0, 0, 464, 430, 1, 0, 0, 0, 464, 431, 1, 0, 0, 0, 464, 442, 1, 0, 0, 0, 464, 453, 1, 0, 0, 0, 465, 69, 1, 0, 0, 0, 466, 469, 5, 47, 0, 0, 467, 469, 5, 64, 0, 0, 468, 466, 1, 0, 0, 0, 468, 467, 1, 0, 0, 0, 469, 71, 1, 0, 0, 0, 470, 474, 3, 64, 32, 0, 471, 472, 4, 36, 11, 0, 472, 474, 3, 70, 35, 0, 473, 470, 1, 0, 0, 0, 473, 471, 1, 0, 0, 0, 474, 73, 1, 0, 0, 0, 475, 476, 5, 9, 0, 0, 476, 477, 5, 26, 0, 0, 477, 75, 1, 0, 0, 0, 478, 479, 5, 14, 0, 0, 479, 484, 3, 78, 39, 0, 480, 481, 5, 33, 0, 0, 481, 483, 3, 78, 39, 0, 482, 480, 1, 0, 0, 0, 483, 486, 1, 0, 0, 0, 484, 482, 1, 0, 0, 0, 484, 485, 1, 0, 0, 0, 485, 77, 1, 0, 0, 0, 486, 484, 1, 0, 0, 0, 487, 489, 3, 10, 5, 0, 488, 490, 7, 4, 0, 0, 489, 488, 1, 0, 0, 0, 489, 490, 1, 0, 0, 0, 490, 493, 1, 0, 0, 0, 491, 492, 5, 45, 0, 0, 492, 494, 7, 5, 0, 0, 493, 491, 1, 0, 0, 0, 493, 494, 1, 0, 0, 0, 494, 79, 1, 0, 0, 0, 495, 496, 5, 8, 0, 0, 496, 497, 3, 62, 31, 0, 497, 81, 1, 0, 0, 0, 498, 499, 5, 2, 0, 0, 499, 500, 3, 62, 31, 0, 500, 83, 1, 0, 0, 0, 501, 502, 5, 11, 0, 0, 502, 507, 3, 86, 43, 0, 503, 504, 5, 33, 0, 0, 504, 506, 3, 86, 43, 0, 505, 503, 1, 0, 0, 0, 506, 509, 1, 0, 0, 0, 507, 505, 1, 0, 0, 0, 507, 508, 1, 0, 0, 0, 508, 85, 1, 0, 0, 0, 509, 507, 1, 0, 0, 0, 510, 511, 3, 60, 30, 0, 511, 512, 5, 84, 0, 0, 512, 513, 3, 60, 30, 0, 513, 87, 1, 0, 0, 0, 514, 515, 5, 1, 0, 0, 515, 516, 3, 20, 10, 0, 516, 518, 3, 106, 53, 0, 517, 519, 3, 94, 47, 0, 518, 517, 1, 0, 0, 0, 518, 519, 1, 0, 0, 0, 519, 89, 1, 0, 0, 0, 520, 521, 5, 7, 0, 0, 521, 522, 3, 20, 10, 0, 522, 523, 3, 106, 53, 0, 523, 91, 1, 0, 0, 0, 524, 525, 5, 10, 0, 0, 525, 526, 3, 58, 29, 0, 526, 93, 1, 0, 0, 0, 527, 532, 3, 96, 48, 0, 528, 529, 5, 33, 0, 0, 529, 531, 3, 96, 48, 0, 530, 528, 1, 0, 0, 0, 531, 534, 1, 0, 0, 0, 532, 530, 1, 0, 0, 0, 532, 533, 1, 0, 0, 0, 533, 95, 1, 0, 0, 0, 534, 532, 1, 0, 0, 0, 535, 536, 3, 64, 32, 0, 536, 537, 5, 31, 0, 0, 537, 538, 3, 68, 34, 0, 538, 97, 1, 0, 0, 0, 539, 540, 7, 6, 0, 0, 540, 99, 1, 0, 0, 0, 541, 544, 3, 102, 51, 0, 542, 544, 3, 104, 52, 0, 543, 541, 1, 0, 0, 0, 543, 542, 1, 0, 0, 0, 544, 101, 1, 0, 0, 0, 545, 547, 7, 0, 0, 0, 546, 545, 1, 0, 0, 0, 546, 547, 1, 0, 0, 0, 547, 548, 1, 0, 0, 0, 548, 549, 5, 27, 0, 0, 549, 103, 1, 0, 0, 0, 550, 552, 7, 0, 0, 0, 551, 550, 1, 0, 0, 0, 551, 552, 1, 0, 0, 0, 552, 553, 1, 0, 0, 0, 553, 554, 5, 26, 0, 0, 554, 105, 1, 0, 0, 0, 555, 556, 5, 25, 0, 0, 556, 107, 1, 0, 0, 0, 557, 558, 7, 7, 0, 0, 558, 109, 1, 0, 0, 0, 559, 560, 5, 5, 0, 0, 560, 561, 3, 112, 56, 0, 561, 111, 1, 0, 0, 0, 562, 563, 5, 65, 0, 0, 563, 564, 3, 2, 1, 0, 564, 565, 5, 66, 0, 0, 565, 113, 1, 0, 0, 0, 566, 567, 5, 13, 0, 0, 567, 568, 5, 100, 0, 0, 568, 115, 1, 0, 0, 0, 569, 570, 5, 3, 0, 0, 570, 573, 5, 90, 0, 0, 571, 572, 5, 88, 0, 0, 572, 574, 3, 60, 30, 0, 573, 571, 1, 0, 0, 0, 573, 574, 1, 0, 0, 0, 574, 584, 1, 0, 0, 0, 575, 576, 5, 89, 0, 0, 576, 581, 3, 118, 59, 0, 577, 578, 5, 33, 0, 0, 578, 580, 3, 118, 59, 0, 579, 577, 1, 0, 0, 0, 580, 583, 1, 0, 0, 0, 581, 579, 1, 0, 0, 0, 581, 582, 1, 0, 0, 0, 582, 585, 1, 0, 0, 0, 583, 581, 1, 0, 0, 0, 584, 575, 1, 0, 0, 0, 584, 585, 1, 0, 0, 0, 585, 117, 1, 0, 0, 0, 586, 587, 3, 60, 30, 0, 587, 588, 5, 31, 0, 0, 588, 590, 1, 0, 0, 0, 589, 586, 1, 0, 0, 0, 589, 590, 1, 0, 0, 0, 590, 591, 1, 0, 0, 0, 591, 592, 3, 60, 30, 0, 592, 119, 1, 0, 0, 0, 593, 594, 5, 18, 0, 0, 594, 595, 3, 36, 18, 0, 595, 596, 5, 88, 0, 0, 596, 597, 3, 62, 31, 0, 597, 121, 1, 0, 0, 0, 598, 599, 5, 17, 0, 0, 599, 602, 3, 54, 27, 0, 600, 601, 5, 28, 0, 0, 601, 603, 3, 30, 15, 0, 602, 600, 1, 0, 0, 0, 602, 603, 1, 0, 0, 0, 603, 123, 1, 0, 0, 0, 59, 135, 144, 162, 174, 183, 191, 197, 205, 207, 212, 219, 224, 235, 241, 249, 251, 262, 269, 280, 283, 289, 301, 307, 317, 321, 326, 336, 344, 357, 361, 365, 372, 376, 383, 389, 396, 404, 412, 420, 437, 448, 459, 464, 468, 473, 484, 489, 493, 507, 518, 532, 543, 546, 551, 573, 581, 584, 589, 602] \ No newline at end of file +[4, 1, 119, 603, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 134, 8, 1, 10, 1, 12, 1, 137, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 145, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 163, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 175, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 182, 8, 5, 10, 5, 12, 5, 185, 9, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 192, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 198, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 206, 8, 5, 10, 5, 12, 5, 209, 9, 5, 1, 6, 1, 6, 3, 6, 213, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 220, 8, 6, 1, 6, 1, 6, 1, 6, 3, 6, 225, 8, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 236, 8, 8, 1, 9, 1, 9, 1, 9, 1, 9, 3, 9, 242, 8, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 5, 9, 250, 8, 9, 10, 9, 12, 9, 253, 9, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 263, 8, 10, 1, 10, 1, 10, 1, 10, 5, 10, 268, 8, 10, 10, 10, 12, 10, 271, 9, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 279, 8, 11, 10, 11, 12, 11, 282, 9, 11, 3, 11, 284, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 5, 15, 298, 8, 15, 10, 15, 12, 15, 301, 9, 15, 1, 16, 1, 16, 1, 16, 3, 16, 306, 8, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 5, 17, 314, 8, 17, 10, 17, 12, 17, 317, 9, 17, 1, 17, 3, 17, 320, 8, 17, 1, 18, 1, 18, 1, 18, 3, 18, 325, 8, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 21, 1, 21, 3, 21, 335, 8, 21, 1, 22, 1, 22, 1, 22, 1, 22, 5, 22, 341, 8, 22, 10, 22, 12, 22, 344, 9, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 354, 8, 24, 10, 24, 12, 24, 357, 9, 24, 1, 24, 3, 24, 360, 8, 24, 1, 24, 1, 24, 3, 24, 364, 8, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 3, 26, 371, 8, 26, 1, 26, 1, 26, 3, 26, 375, 8, 26, 1, 27, 1, 27, 1, 27, 5, 27, 380, 8, 27, 10, 27, 12, 27, 383, 9, 27, 1, 28, 1, 28, 1, 28, 3, 28, 388, 8, 28, 1, 29, 1, 29, 1, 29, 5, 29, 393, 8, 29, 10, 29, 12, 29, 396, 9, 29, 1, 30, 1, 30, 1, 30, 5, 30, 401, 8, 30, 10, 30, 12, 30, 404, 9, 30, 1, 31, 1, 31, 1, 31, 5, 31, 409, 8, 31, 10, 31, 12, 31, 412, 9, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 3, 33, 419, 8, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 434, 8, 34, 10, 34, 12, 34, 437, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 445, 8, 34, 10, 34, 12, 34, 448, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 456, 8, 34, 10, 34, 12, 34, 459, 9, 34, 1, 34, 1, 34, 3, 34, 463, 8, 34, 1, 35, 1, 35, 3, 35, 467, 8, 35, 1, 36, 1, 36, 1, 36, 3, 36, 472, 8, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 481, 8, 38, 10, 38, 12, 38, 484, 9, 38, 1, 39, 1, 39, 3, 39, 488, 8, 39, 1, 39, 1, 39, 3, 39, 492, 8, 39, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 5, 42, 504, 8, 42, 10, 42, 12, 42, 507, 9, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 3, 44, 517, 8, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 5, 47, 529, 8, 47, 10, 47, 12, 47, 532, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 50, 1, 50, 3, 50, 542, 8, 50, 1, 51, 3, 51, 545, 8, 51, 1, 51, 1, 51, 1, 52, 3, 52, 550, 8, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 572, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 5, 58, 578, 8, 58, 10, 58, 12, 58, 581, 9, 58, 3, 58, 583, 8, 58, 1, 59, 1, 59, 1, 59, 3, 59, 588, 8, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 3, 61, 601, 8, 61, 1, 61, 0, 4, 2, 10, 18, 20, 62, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 0, 8, 1, 0, 59, 60, 1, 0, 61, 63, 2, 0, 26, 26, 76, 76, 1, 0, 67, 68, 2, 0, 31, 31, 35, 35, 2, 0, 38, 38, 41, 41, 2, 0, 37, 37, 51, 51, 2, 0, 52, 52, 54, 58, 628, 0, 124, 1, 0, 0, 0, 2, 127, 1, 0, 0, 0, 4, 144, 1, 0, 0, 0, 6, 162, 1, 0, 0, 0, 8, 164, 1, 0, 0, 0, 10, 197, 1, 0, 0, 0, 12, 224, 1, 0, 0, 0, 14, 226, 1, 0, 0, 0, 16, 235, 1, 0, 0, 0, 18, 241, 1, 0, 0, 0, 20, 262, 1, 0, 0, 0, 22, 272, 1, 0, 0, 0, 24, 287, 1, 0, 0, 0, 26, 289, 1, 0, 0, 0, 28, 291, 1, 0, 0, 0, 30, 294, 1, 0, 0, 0, 32, 305, 1, 0, 0, 0, 34, 309, 1, 0, 0, 0, 36, 324, 1, 0, 0, 0, 38, 328, 1, 0, 0, 0, 40, 330, 1, 0, 0, 0, 42, 334, 1, 0, 0, 0, 44, 336, 1, 0, 0, 0, 46, 345, 1, 0, 0, 0, 48, 349, 1, 0, 0, 0, 50, 365, 1, 0, 0, 0, 52, 368, 1, 0, 0, 0, 54, 376, 1, 0, 0, 0, 56, 384, 1, 0, 0, 0, 58, 389, 1, 0, 0, 0, 60, 397, 1, 0, 0, 0, 62, 405, 1, 0, 0, 0, 64, 413, 1, 0, 0, 0, 66, 418, 1, 0, 0, 0, 68, 462, 1, 0, 0, 0, 70, 466, 1, 0, 0, 0, 72, 471, 1, 0, 0, 0, 74, 473, 1, 0, 0, 0, 76, 476, 1, 0, 0, 0, 78, 485, 1, 0, 0, 0, 80, 493, 1, 0, 0, 0, 82, 496, 1, 0, 0, 0, 84, 499, 1, 0, 0, 0, 86, 508, 1, 0, 0, 0, 88, 512, 1, 0, 0, 0, 90, 518, 1, 0, 0, 0, 92, 522, 1, 0, 0, 0, 94, 525, 1, 0, 0, 0, 96, 533, 1, 0, 0, 0, 98, 537, 1, 0, 0, 0, 100, 541, 1, 0, 0, 0, 102, 544, 1, 0, 0, 0, 104, 549, 1, 0, 0, 0, 106, 553, 1, 0, 0, 0, 108, 555, 1, 0, 0, 0, 110, 557, 1, 0, 0, 0, 112, 560, 1, 0, 0, 0, 114, 564, 1, 0, 0, 0, 116, 567, 1, 0, 0, 0, 118, 587, 1, 0, 0, 0, 120, 591, 1, 0, 0, 0, 122, 596, 1, 0, 0, 0, 124, 125, 3, 2, 1, 0, 125, 126, 5, 0, 0, 1, 126, 1, 1, 0, 0, 0, 127, 128, 6, 1, -1, 0, 128, 129, 3, 4, 2, 0, 129, 135, 1, 0, 0, 0, 130, 131, 10, 1, 0, 0, 131, 132, 5, 25, 0, 0, 132, 134, 3, 6, 3, 0, 133, 130, 1, 0, 0, 0, 134, 137, 1, 0, 0, 0, 135, 133, 1, 0, 0, 0, 135, 136, 1, 0, 0, 0, 136, 3, 1, 0, 0, 0, 137, 135, 1, 0, 0, 0, 138, 145, 3, 110, 55, 0, 139, 145, 3, 34, 17, 0, 140, 145, 3, 28, 14, 0, 141, 145, 3, 114, 57, 0, 142, 143, 4, 2, 1, 0, 143, 145, 3, 48, 24, 0, 144, 138, 1, 0, 0, 0, 144, 139, 1, 0, 0, 0, 144, 140, 1, 0, 0, 0, 144, 141, 1, 0, 0, 0, 144, 142, 1, 0, 0, 0, 145, 5, 1, 0, 0, 0, 146, 163, 3, 50, 25, 0, 147, 163, 3, 8, 4, 0, 148, 163, 3, 80, 40, 0, 149, 163, 3, 74, 37, 0, 150, 163, 3, 52, 26, 0, 151, 163, 3, 76, 38, 0, 152, 163, 3, 82, 41, 0, 153, 163, 3, 84, 42, 0, 154, 163, 3, 88, 44, 0, 155, 163, 3, 90, 45, 0, 156, 163, 3, 116, 58, 0, 157, 163, 3, 92, 46, 0, 158, 159, 4, 3, 2, 0, 159, 163, 3, 122, 61, 0, 160, 161, 4, 3, 3, 0, 161, 163, 3, 120, 60, 0, 162, 146, 1, 0, 0, 0, 162, 147, 1, 0, 0, 0, 162, 148, 1, 0, 0, 0, 162, 149, 1, 0, 0, 0, 162, 150, 1, 0, 0, 0, 162, 151, 1, 0, 0, 0, 162, 152, 1, 0, 0, 0, 162, 153, 1, 0, 0, 0, 162, 154, 1, 0, 0, 0, 162, 155, 1, 0, 0, 0, 162, 156, 1, 0, 0, 0, 162, 157, 1, 0, 0, 0, 162, 158, 1, 0, 0, 0, 162, 160, 1, 0, 0, 0, 163, 7, 1, 0, 0, 0, 164, 165, 5, 16, 0, 0, 165, 166, 3, 10, 5, 0, 166, 9, 1, 0, 0, 0, 167, 168, 6, 5, -1, 0, 168, 169, 5, 44, 0, 0, 169, 198, 3, 10, 5, 8, 170, 198, 3, 16, 8, 0, 171, 198, 3, 12, 6, 0, 172, 174, 3, 16, 8, 0, 173, 175, 5, 44, 0, 0, 174, 173, 1, 0, 0, 0, 174, 175, 1, 0, 0, 0, 175, 176, 1, 0, 0, 0, 176, 177, 5, 39, 0, 0, 177, 178, 5, 43, 0, 0, 178, 183, 3, 16, 8, 0, 179, 180, 5, 34, 0, 0, 180, 182, 3, 16, 8, 0, 181, 179, 1, 0, 0, 0, 182, 185, 1, 0, 0, 0, 183, 181, 1, 0, 0, 0, 183, 184, 1, 0, 0, 0, 184, 186, 1, 0, 0, 0, 185, 183, 1, 0, 0, 0, 186, 187, 5, 50, 0, 0, 187, 198, 1, 0, 0, 0, 188, 189, 3, 16, 8, 0, 189, 191, 5, 40, 0, 0, 190, 192, 5, 44, 0, 0, 191, 190, 1, 0, 0, 0, 191, 192, 1, 0, 0, 0, 192, 193, 1, 0, 0, 0, 193, 194, 5, 45, 0, 0, 194, 198, 1, 0, 0, 0, 195, 196, 4, 5, 4, 0, 196, 198, 3, 14, 7, 0, 197, 167, 1, 0, 0, 0, 197, 170, 1, 0, 0, 0, 197, 171, 1, 0, 0, 0, 197, 172, 1, 0, 0, 0, 197, 188, 1, 0, 0, 0, 197, 195, 1, 0, 0, 0, 198, 207, 1, 0, 0, 0, 199, 200, 10, 5, 0, 0, 200, 201, 5, 30, 0, 0, 201, 206, 3, 10, 5, 6, 202, 203, 10, 4, 0, 0, 203, 204, 5, 47, 0, 0, 204, 206, 3, 10, 5, 5, 205, 199, 1, 0, 0, 0, 205, 202, 1, 0, 0, 0, 206, 209, 1, 0, 0, 0, 207, 205, 1, 0, 0, 0, 207, 208, 1, 0, 0, 0, 208, 11, 1, 0, 0, 0, 209, 207, 1, 0, 0, 0, 210, 212, 3, 16, 8, 0, 211, 213, 5, 44, 0, 0, 212, 211, 1, 0, 0, 0, 212, 213, 1, 0, 0, 0, 213, 214, 1, 0, 0, 0, 214, 215, 5, 42, 0, 0, 215, 216, 3, 106, 53, 0, 216, 225, 1, 0, 0, 0, 217, 219, 3, 16, 8, 0, 218, 220, 5, 44, 0, 0, 219, 218, 1, 0, 0, 0, 219, 220, 1, 0, 0, 0, 220, 221, 1, 0, 0, 0, 221, 222, 5, 49, 0, 0, 222, 223, 3, 106, 53, 0, 223, 225, 1, 0, 0, 0, 224, 210, 1, 0, 0, 0, 224, 217, 1, 0, 0, 0, 225, 13, 1, 0, 0, 0, 226, 227, 3, 58, 29, 0, 227, 228, 5, 24, 0, 0, 228, 229, 3, 68, 34, 0, 229, 15, 1, 0, 0, 0, 230, 236, 3, 18, 9, 0, 231, 232, 3, 18, 9, 0, 232, 233, 3, 108, 54, 0, 233, 234, 3, 18, 9, 0, 234, 236, 1, 0, 0, 0, 235, 230, 1, 0, 0, 0, 235, 231, 1, 0, 0, 0, 236, 17, 1, 0, 0, 0, 237, 238, 6, 9, -1, 0, 238, 242, 3, 20, 10, 0, 239, 240, 7, 0, 0, 0, 240, 242, 3, 18, 9, 3, 241, 237, 1, 0, 0, 0, 241, 239, 1, 0, 0, 0, 242, 251, 1, 0, 0, 0, 243, 244, 10, 2, 0, 0, 244, 245, 7, 1, 0, 0, 245, 250, 3, 18, 9, 3, 246, 247, 10, 1, 0, 0, 247, 248, 7, 0, 0, 0, 248, 250, 3, 18, 9, 2, 249, 243, 1, 0, 0, 0, 249, 246, 1, 0, 0, 0, 250, 253, 1, 0, 0, 0, 251, 249, 1, 0, 0, 0, 251, 252, 1, 0, 0, 0, 252, 19, 1, 0, 0, 0, 253, 251, 1, 0, 0, 0, 254, 255, 6, 10, -1, 0, 255, 263, 3, 68, 34, 0, 256, 263, 3, 58, 29, 0, 257, 263, 3, 22, 11, 0, 258, 259, 5, 43, 0, 0, 259, 260, 3, 10, 5, 0, 260, 261, 5, 50, 0, 0, 261, 263, 1, 0, 0, 0, 262, 254, 1, 0, 0, 0, 262, 256, 1, 0, 0, 0, 262, 257, 1, 0, 0, 0, 262, 258, 1, 0, 0, 0, 263, 269, 1, 0, 0, 0, 264, 265, 10, 1, 0, 0, 265, 266, 5, 33, 0, 0, 266, 268, 3, 26, 13, 0, 267, 264, 1, 0, 0, 0, 268, 271, 1, 0, 0, 0, 269, 267, 1, 0, 0, 0, 269, 270, 1, 0, 0, 0, 270, 21, 1, 0, 0, 0, 271, 269, 1, 0, 0, 0, 272, 273, 3, 24, 12, 0, 273, 283, 5, 43, 0, 0, 274, 284, 5, 61, 0, 0, 275, 280, 3, 10, 5, 0, 276, 277, 5, 34, 0, 0, 277, 279, 3, 10, 5, 0, 278, 276, 1, 0, 0, 0, 279, 282, 1, 0, 0, 0, 280, 278, 1, 0, 0, 0, 280, 281, 1, 0, 0, 0, 281, 284, 1, 0, 0, 0, 282, 280, 1, 0, 0, 0, 283, 274, 1, 0, 0, 0, 283, 275, 1, 0, 0, 0, 283, 284, 1, 0, 0, 0, 284, 285, 1, 0, 0, 0, 285, 286, 5, 50, 0, 0, 286, 23, 1, 0, 0, 0, 287, 288, 3, 72, 36, 0, 288, 25, 1, 0, 0, 0, 289, 290, 3, 64, 32, 0, 290, 27, 1, 0, 0, 0, 291, 292, 5, 12, 0, 0, 292, 293, 3, 30, 15, 0, 293, 29, 1, 0, 0, 0, 294, 299, 3, 32, 16, 0, 295, 296, 5, 34, 0, 0, 296, 298, 3, 32, 16, 0, 297, 295, 1, 0, 0, 0, 298, 301, 1, 0, 0, 0, 299, 297, 1, 0, 0, 0, 299, 300, 1, 0, 0, 0, 300, 31, 1, 0, 0, 0, 301, 299, 1, 0, 0, 0, 302, 303, 3, 58, 29, 0, 303, 304, 5, 32, 0, 0, 304, 306, 1, 0, 0, 0, 305, 302, 1, 0, 0, 0, 305, 306, 1, 0, 0, 0, 306, 307, 1, 0, 0, 0, 307, 308, 3, 10, 5, 0, 308, 33, 1, 0, 0, 0, 309, 310, 5, 6, 0, 0, 310, 315, 3, 36, 18, 0, 311, 312, 5, 34, 0, 0, 312, 314, 3, 36, 18, 0, 313, 311, 1, 0, 0, 0, 314, 317, 1, 0, 0, 0, 315, 313, 1, 0, 0, 0, 315, 316, 1, 0, 0, 0, 316, 319, 1, 0, 0, 0, 317, 315, 1, 0, 0, 0, 318, 320, 3, 42, 21, 0, 319, 318, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 35, 1, 0, 0, 0, 321, 322, 3, 38, 19, 0, 322, 323, 5, 24, 0, 0, 323, 325, 1, 0, 0, 0, 324, 321, 1, 0, 0, 0, 324, 325, 1, 0, 0, 0, 325, 326, 1, 0, 0, 0, 326, 327, 3, 40, 20, 0, 327, 37, 1, 0, 0, 0, 328, 329, 5, 76, 0, 0, 329, 39, 1, 0, 0, 0, 330, 331, 7, 2, 0, 0, 331, 41, 1, 0, 0, 0, 332, 335, 3, 44, 22, 0, 333, 335, 3, 46, 23, 0, 334, 332, 1, 0, 0, 0, 334, 333, 1, 0, 0, 0, 335, 43, 1, 0, 0, 0, 336, 337, 5, 75, 0, 0, 337, 342, 5, 76, 0, 0, 338, 339, 5, 34, 0, 0, 339, 341, 5, 76, 0, 0, 340, 338, 1, 0, 0, 0, 341, 344, 1, 0, 0, 0, 342, 340, 1, 0, 0, 0, 342, 343, 1, 0, 0, 0, 343, 45, 1, 0, 0, 0, 344, 342, 1, 0, 0, 0, 345, 346, 5, 65, 0, 0, 346, 347, 3, 44, 22, 0, 347, 348, 5, 66, 0, 0, 348, 47, 1, 0, 0, 0, 349, 350, 5, 19, 0, 0, 350, 355, 3, 36, 18, 0, 351, 352, 5, 34, 0, 0, 352, 354, 3, 36, 18, 0, 353, 351, 1, 0, 0, 0, 354, 357, 1, 0, 0, 0, 355, 353, 1, 0, 0, 0, 355, 356, 1, 0, 0, 0, 356, 359, 1, 0, 0, 0, 357, 355, 1, 0, 0, 0, 358, 360, 3, 54, 27, 0, 359, 358, 1, 0, 0, 0, 359, 360, 1, 0, 0, 0, 360, 363, 1, 0, 0, 0, 361, 362, 5, 29, 0, 0, 362, 364, 3, 30, 15, 0, 363, 361, 1, 0, 0, 0, 363, 364, 1, 0, 0, 0, 364, 49, 1, 0, 0, 0, 365, 366, 5, 4, 0, 0, 366, 367, 3, 30, 15, 0, 367, 51, 1, 0, 0, 0, 368, 370, 5, 15, 0, 0, 369, 371, 3, 54, 27, 0, 370, 369, 1, 0, 0, 0, 370, 371, 1, 0, 0, 0, 371, 374, 1, 0, 0, 0, 372, 373, 5, 29, 0, 0, 373, 375, 3, 30, 15, 0, 374, 372, 1, 0, 0, 0, 374, 375, 1, 0, 0, 0, 375, 53, 1, 0, 0, 0, 376, 381, 3, 56, 28, 0, 377, 378, 5, 34, 0, 0, 378, 380, 3, 56, 28, 0, 379, 377, 1, 0, 0, 0, 380, 383, 1, 0, 0, 0, 381, 379, 1, 0, 0, 0, 381, 382, 1, 0, 0, 0, 382, 55, 1, 0, 0, 0, 383, 381, 1, 0, 0, 0, 384, 387, 3, 32, 16, 0, 385, 386, 5, 16, 0, 0, 386, 388, 3, 10, 5, 0, 387, 385, 1, 0, 0, 0, 387, 388, 1, 0, 0, 0, 388, 57, 1, 0, 0, 0, 389, 394, 3, 72, 36, 0, 390, 391, 5, 36, 0, 0, 391, 393, 3, 72, 36, 0, 392, 390, 1, 0, 0, 0, 393, 396, 1, 0, 0, 0, 394, 392, 1, 0, 0, 0, 394, 395, 1, 0, 0, 0, 395, 59, 1, 0, 0, 0, 396, 394, 1, 0, 0, 0, 397, 402, 3, 66, 33, 0, 398, 399, 5, 36, 0, 0, 399, 401, 3, 66, 33, 0, 400, 398, 1, 0, 0, 0, 401, 404, 1, 0, 0, 0, 402, 400, 1, 0, 0, 0, 402, 403, 1, 0, 0, 0, 403, 61, 1, 0, 0, 0, 404, 402, 1, 0, 0, 0, 405, 410, 3, 60, 30, 0, 406, 407, 5, 34, 0, 0, 407, 409, 3, 60, 30, 0, 408, 406, 1, 0, 0, 0, 409, 412, 1, 0, 0, 0, 410, 408, 1, 0, 0, 0, 410, 411, 1, 0, 0, 0, 411, 63, 1, 0, 0, 0, 412, 410, 1, 0, 0, 0, 413, 414, 7, 3, 0, 0, 414, 65, 1, 0, 0, 0, 415, 419, 5, 80, 0, 0, 416, 417, 4, 33, 10, 0, 417, 419, 3, 70, 35, 0, 418, 415, 1, 0, 0, 0, 418, 416, 1, 0, 0, 0, 419, 67, 1, 0, 0, 0, 420, 463, 5, 45, 0, 0, 421, 422, 3, 104, 52, 0, 422, 423, 5, 67, 0, 0, 423, 463, 1, 0, 0, 0, 424, 463, 3, 102, 51, 0, 425, 463, 3, 104, 52, 0, 426, 463, 3, 98, 49, 0, 427, 463, 3, 70, 35, 0, 428, 463, 3, 106, 53, 0, 429, 430, 5, 65, 0, 0, 430, 435, 3, 100, 50, 0, 431, 432, 5, 34, 0, 0, 432, 434, 3, 100, 50, 0, 433, 431, 1, 0, 0, 0, 434, 437, 1, 0, 0, 0, 435, 433, 1, 0, 0, 0, 435, 436, 1, 0, 0, 0, 436, 438, 1, 0, 0, 0, 437, 435, 1, 0, 0, 0, 438, 439, 5, 66, 0, 0, 439, 463, 1, 0, 0, 0, 440, 441, 5, 65, 0, 0, 441, 446, 3, 98, 49, 0, 442, 443, 5, 34, 0, 0, 443, 445, 3, 98, 49, 0, 444, 442, 1, 0, 0, 0, 445, 448, 1, 0, 0, 0, 446, 444, 1, 0, 0, 0, 446, 447, 1, 0, 0, 0, 447, 449, 1, 0, 0, 0, 448, 446, 1, 0, 0, 0, 449, 450, 5, 66, 0, 0, 450, 463, 1, 0, 0, 0, 451, 452, 5, 65, 0, 0, 452, 457, 3, 106, 53, 0, 453, 454, 5, 34, 0, 0, 454, 456, 3, 106, 53, 0, 455, 453, 1, 0, 0, 0, 456, 459, 1, 0, 0, 0, 457, 455, 1, 0, 0, 0, 457, 458, 1, 0, 0, 0, 458, 460, 1, 0, 0, 0, 459, 457, 1, 0, 0, 0, 460, 461, 5, 66, 0, 0, 461, 463, 1, 0, 0, 0, 462, 420, 1, 0, 0, 0, 462, 421, 1, 0, 0, 0, 462, 424, 1, 0, 0, 0, 462, 425, 1, 0, 0, 0, 462, 426, 1, 0, 0, 0, 462, 427, 1, 0, 0, 0, 462, 428, 1, 0, 0, 0, 462, 429, 1, 0, 0, 0, 462, 440, 1, 0, 0, 0, 462, 451, 1, 0, 0, 0, 463, 69, 1, 0, 0, 0, 464, 467, 5, 48, 0, 0, 465, 467, 5, 64, 0, 0, 466, 464, 1, 0, 0, 0, 466, 465, 1, 0, 0, 0, 467, 71, 1, 0, 0, 0, 468, 472, 3, 64, 32, 0, 469, 470, 4, 36, 11, 0, 470, 472, 3, 70, 35, 0, 471, 468, 1, 0, 0, 0, 471, 469, 1, 0, 0, 0, 472, 73, 1, 0, 0, 0, 473, 474, 5, 9, 0, 0, 474, 475, 5, 27, 0, 0, 475, 75, 1, 0, 0, 0, 476, 477, 5, 14, 0, 0, 477, 482, 3, 78, 39, 0, 478, 479, 5, 34, 0, 0, 479, 481, 3, 78, 39, 0, 480, 478, 1, 0, 0, 0, 481, 484, 1, 0, 0, 0, 482, 480, 1, 0, 0, 0, 482, 483, 1, 0, 0, 0, 483, 77, 1, 0, 0, 0, 484, 482, 1, 0, 0, 0, 485, 487, 3, 10, 5, 0, 486, 488, 7, 4, 0, 0, 487, 486, 1, 0, 0, 0, 487, 488, 1, 0, 0, 0, 488, 491, 1, 0, 0, 0, 489, 490, 5, 46, 0, 0, 490, 492, 7, 5, 0, 0, 491, 489, 1, 0, 0, 0, 491, 492, 1, 0, 0, 0, 492, 79, 1, 0, 0, 0, 493, 494, 5, 8, 0, 0, 494, 495, 3, 62, 31, 0, 495, 81, 1, 0, 0, 0, 496, 497, 5, 2, 0, 0, 497, 498, 3, 62, 31, 0, 498, 83, 1, 0, 0, 0, 499, 500, 5, 11, 0, 0, 500, 505, 3, 86, 43, 0, 501, 502, 5, 34, 0, 0, 502, 504, 3, 86, 43, 0, 503, 501, 1, 0, 0, 0, 504, 507, 1, 0, 0, 0, 505, 503, 1, 0, 0, 0, 505, 506, 1, 0, 0, 0, 506, 85, 1, 0, 0, 0, 507, 505, 1, 0, 0, 0, 508, 509, 3, 60, 30, 0, 509, 510, 5, 84, 0, 0, 510, 511, 3, 60, 30, 0, 511, 87, 1, 0, 0, 0, 512, 513, 5, 1, 0, 0, 513, 514, 3, 20, 10, 0, 514, 516, 3, 106, 53, 0, 515, 517, 3, 94, 47, 0, 516, 515, 1, 0, 0, 0, 516, 517, 1, 0, 0, 0, 517, 89, 1, 0, 0, 0, 518, 519, 5, 7, 0, 0, 519, 520, 3, 20, 10, 0, 520, 521, 3, 106, 53, 0, 521, 91, 1, 0, 0, 0, 522, 523, 5, 10, 0, 0, 523, 524, 3, 58, 29, 0, 524, 93, 1, 0, 0, 0, 525, 530, 3, 96, 48, 0, 526, 527, 5, 34, 0, 0, 527, 529, 3, 96, 48, 0, 528, 526, 1, 0, 0, 0, 529, 532, 1, 0, 0, 0, 530, 528, 1, 0, 0, 0, 530, 531, 1, 0, 0, 0, 531, 95, 1, 0, 0, 0, 532, 530, 1, 0, 0, 0, 533, 534, 3, 64, 32, 0, 534, 535, 5, 32, 0, 0, 535, 536, 3, 68, 34, 0, 536, 97, 1, 0, 0, 0, 537, 538, 7, 6, 0, 0, 538, 99, 1, 0, 0, 0, 539, 542, 3, 102, 51, 0, 540, 542, 3, 104, 52, 0, 541, 539, 1, 0, 0, 0, 541, 540, 1, 0, 0, 0, 542, 101, 1, 0, 0, 0, 543, 545, 7, 0, 0, 0, 544, 543, 1, 0, 0, 0, 544, 545, 1, 0, 0, 0, 545, 546, 1, 0, 0, 0, 546, 547, 5, 28, 0, 0, 547, 103, 1, 0, 0, 0, 548, 550, 7, 0, 0, 0, 549, 548, 1, 0, 0, 0, 549, 550, 1, 0, 0, 0, 550, 551, 1, 0, 0, 0, 551, 552, 5, 27, 0, 0, 552, 105, 1, 0, 0, 0, 553, 554, 5, 26, 0, 0, 554, 107, 1, 0, 0, 0, 555, 556, 7, 7, 0, 0, 556, 109, 1, 0, 0, 0, 557, 558, 5, 5, 0, 0, 558, 559, 3, 112, 56, 0, 559, 111, 1, 0, 0, 0, 560, 561, 5, 65, 0, 0, 561, 562, 3, 2, 1, 0, 562, 563, 5, 66, 0, 0, 563, 113, 1, 0, 0, 0, 564, 565, 5, 13, 0, 0, 565, 566, 5, 100, 0, 0, 566, 115, 1, 0, 0, 0, 567, 568, 5, 3, 0, 0, 568, 571, 5, 90, 0, 0, 569, 570, 5, 88, 0, 0, 570, 572, 3, 60, 30, 0, 571, 569, 1, 0, 0, 0, 571, 572, 1, 0, 0, 0, 572, 582, 1, 0, 0, 0, 573, 574, 5, 89, 0, 0, 574, 579, 3, 118, 59, 0, 575, 576, 5, 34, 0, 0, 576, 578, 3, 118, 59, 0, 577, 575, 1, 0, 0, 0, 578, 581, 1, 0, 0, 0, 579, 577, 1, 0, 0, 0, 579, 580, 1, 0, 0, 0, 580, 583, 1, 0, 0, 0, 581, 579, 1, 0, 0, 0, 582, 573, 1, 0, 0, 0, 582, 583, 1, 0, 0, 0, 583, 117, 1, 0, 0, 0, 584, 585, 3, 60, 30, 0, 585, 586, 5, 32, 0, 0, 586, 588, 1, 0, 0, 0, 587, 584, 1, 0, 0, 0, 587, 588, 1, 0, 0, 0, 588, 589, 1, 0, 0, 0, 589, 590, 3, 60, 30, 0, 590, 119, 1, 0, 0, 0, 591, 592, 5, 18, 0, 0, 592, 593, 3, 36, 18, 0, 593, 594, 5, 88, 0, 0, 594, 595, 3, 62, 31, 0, 595, 121, 1, 0, 0, 0, 596, 597, 5, 17, 0, 0, 597, 600, 3, 54, 27, 0, 598, 599, 5, 29, 0, 0, 599, 601, 3, 30, 15, 0, 600, 598, 1, 0, 0, 0, 600, 601, 1, 0, 0, 0, 601, 123, 1, 0, 0, 0, 58, 135, 144, 162, 174, 183, 191, 197, 205, 207, 212, 219, 224, 235, 241, 249, 251, 262, 269, 280, 283, 299, 305, 315, 319, 324, 334, 342, 355, 359, 363, 370, 374, 381, 387, 394, 402, 410, 418, 435, 446, 457, 462, 466, 471, 482, 487, 491, 505, 516, 530, 541, 544, 549, 571, 579, 582, 587, 600] \ No newline at end of file diff --git a/packages/kbn-esql-ast/src/antlr/esql_parser.tokens b/packages/kbn-esql-ast/src/antlr/esql_parser.tokens index 4d1f42628914..3dd1a2c75403 100644 --- a/packages/kbn-esql-ast/src/antlr/esql_parser.tokens +++ b/packages/kbn-esql-ast/src/antlr/esql_parser.tokens @@ -21,46 +21,46 @@ UNKNOWN_CMD=20 LINE_COMMENT=21 MULTILINE_COMMENT=22 WS=23 -PIPE=24 -QUOTED_STRING=25 -INTEGER_LITERAL=26 -DECIMAL_LITERAL=27 -BY=28 -AND=29 -ASC=30 -ASSIGN=31 -CAST_OP=32 -COMMA=33 -DESC=34 -DOT=35 -FALSE=36 -FIRST=37 -IN=38 -IS=39 -LAST=40 -LIKE=41 -LP=42 -NOT=43 -NULL=44 -NULLS=45 -OR=46 -PARAM=47 -RLIKE=48 -RP=49 -TRUE=50 -EQ=51 -CIEQ=52 -NEQ=53 -LT=54 -LTE=55 -GT=56 -GTE=57 -PLUS=58 -MINUS=59 -ASTERISK=60 -SLASH=61 -PERCENT=62 -MATCH=63 +COLON=24 +PIPE=25 +QUOTED_STRING=26 +INTEGER_LITERAL=27 +DECIMAL_LITERAL=28 +BY=29 +AND=30 +ASC=31 +ASSIGN=32 +CAST_OP=33 +COMMA=34 +DESC=35 +DOT=36 +FALSE=37 +FIRST=38 +IN=39 +IS=40 +LAST=41 +LIKE=42 +LP=43 +NOT=44 +NULL=45 +NULLS=46 +OR=47 +PARAM=48 +RLIKE=49 +RP=50 +TRUE=51 +EQ=52 +CIEQ=53 +NEQ=54 +LT=55 +LTE=56 +GT=57 +GTE=58 +PLUS=59 +MINUS=60 +ASTERISK=61 +SLASH=62 +PERCENT=63 NAMED_OR_POSITIONAL_PARAM=64 OPENING_BRACKET=65 CLOSING_BRACKET=66 @@ -101,23 +101,22 @@ INFO=100 SHOW_LINE_COMMENT=101 SHOW_MULTILINE_COMMENT=102 SHOW_WS=103 -COLON=104 -SETTING=105 -SETTING_LINE_COMMENT=106 -SETTTING_MULTILINE_COMMENT=107 -SETTING_WS=108 -LOOKUP_LINE_COMMENT=109 -LOOKUP_MULTILINE_COMMENT=110 -LOOKUP_WS=111 -LOOKUP_FIELD_LINE_COMMENT=112 -LOOKUP_FIELD_MULTILINE_COMMENT=113 -LOOKUP_FIELD_WS=114 -METRICS_LINE_COMMENT=115 -METRICS_MULTILINE_COMMENT=116 -METRICS_WS=117 -CLOSING_METRICS_LINE_COMMENT=118 -CLOSING_METRICS_MULTILINE_COMMENT=119 -CLOSING_METRICS_WS=120 +SETTING=104 +SETTING_LINE_COMMENT=105 +SETTTING_MULTILINE_COMMENT=106 +SETTING_WS=107 +LOOKUP_LINE_COMMENT=108 +LOOKUP_MULTILINE_COMMENT=109 +LOOKUP_WS=110 +LOOKUP_FIELD_LINE_COMMENT=111 +LOOKUP_FIELD_MULTILINE_COMMENT=112 +LOOKUP_FIELD_WS=113 +METRICS_LINE_COMMENT=114 +METRICS_MULTILINE_COMMENT=115 +METRICS_WS=116 +CLOSING_METRICS_LINE_COMMENT=117 +CLOSING_METRICS_MULTILINE_COMMENT=118 +CLOSING_METRICS_WS=119 'dissect'=1 'drop'=2 'enrich'=3 @@ -134,47 +133,46 @@ CLOSING_METRICS_WS=120 'sort'=14 'stats'=15 'where'=16 -'|'=24 -'by'=28 -'and'=29 -'asc'=30 -'='=31 -'::'=32 -','=33 -'desc'=34 -'.'=35 -'false'=36 -'first'=37 -'in'=38 -'is'=39 -'last'=40 -'like'=41 -'('=42 -'not'=43 -'null'=44 -'nulls'=45 -'or'=46 -'?'=47 -'rlike'=48 -')'=49 -'true'=50 -'=='=51 -'=~'=52 -'!='=53 -'<'=54 -'<='=55 -'>'=56 -'>='=57 -'+'=58 -'-'=59 -'*'=60 -'/'=61 -'%'=62 -'match'=63 +':'=24 +'|'=25 +'by'=29 +'and'=30 +'asc'=31 +'='=32 +'::'=33 +','=34 +'desc'=35 +'.'=36 +'false'=37 +'first'=38 +'in'=39 +'is'=40 +'last'=41 +'like'=42 +'('=43 +'not'=44 +'null'=45 +'nulls'=46 +'or'=47 +'?'=48 +'rlike'=49 +')'=50 +'true'=51 +'=='=52 +'=~'=53 +'!='=54 +'<'=55 +'<='=56 +'>'=57 +'>='=58 +'+'=59 +'-'=60 +'*'=61 +'/'=62 +'%'=63 ']'=66 'metadata'=75 'as'=84 'on'=88 'with'=89 'info'=100 -':'=104 diff --git a/packages/kbn-esql-ast/src/antlr/esql_parser.ts b/packages/kbn-esql-ast/src/antlr/esql_parser.ts index b0af12e1ebc1..4dc0c5c628e3 100644 --- a/packages/kbn-esql-ast/src/antlr/esql_parser.ts +++ b/packages/kbn-esql-ast/src/antlr/esql_parser.ts @@ -51,46 +51,46 @@ export default class esql_parser extends parser_config { public static readonly LINE_COMMENT = 21; public static readonly MULTILINE_COMMENT = 22; public static readonly WS = 23; - public static readonly PIPE = 24; - public static readonly QUOTED_STRING = 25; - public static readonly INTEGER_LITERAL = 26; - public static readonly DECIMAL_LITERAL = 27; - public static readonly BY = 28; - public static readonly AND = 29; - public static readonly ASC = 30; - public static readonly ASSIGN = 31; - public static readonly CAST_OP = 32; - public static readonly COMMA = 33; - public static readonly DESC = 34; - public static readonly DOT = 35; - public static readonly FALSE = 36; - public static readonly FIRST = 37; - public static readonly IN = 38; - public static readonly IS = 39; - public static readonly LAST = 40; - public static readonly LIKE = 41; - public static readonly LP = 42; - public static readonly NOT = 43; - public static readonly NULL = 44; - public static readonly NULLS = 45; - public static readonly OR = 46; - public static readonly PARAM = 47; - public static readonly RLIKE = 48; - public static readonly RP = 49; - public static readonly TRUE = 50; - public static readonly EQ = 51; - public static readonly CIEQ = 52; - public static readonly NEQ = 53; - public static readonly LT = 54; - public static readonly LTE = 55; - public static readonly GT = 56; - public static readonly GTE = 57; - public static readonly PLUS = 58; - public static readonly MINUS = 59; - public static readonly ASTERISK = 60; - public static readonly SLASH = 61; - public static readonly PERCENT = 62; - public static readonly MATCH = 63; + public static readonly COLON = 24; + public static readonly PIPE = 25; + public static readonly QUOTED_STRING = 26; + public static readonly INTEGER_LITERAL = 27; + public static readonly DECIMAL_LITERAL = 28; + public static readonly BY = 29; + public static readonly AND = 30; + public static readonly ASC = 31; + public static readonly ASSIGN = 32; + public static readonly CAST_OP = 33; + public static readonly COMMA = 34; + public static readonly DESC = 35; + public static readonly DOT = 36; + public static readonly FALSE = 37; + public static readonly FIRST = 38; + public static readonly IN = 39; + public static readonly IS = 40; + public static readonly LAST = 41; + public static readonly LIKE = 42; + public static readonly LP = 43; + public static readonly NOT = 44; + public static readonly NULL = 45; + public static readonly NULLS = 46; + public static readonly OR = 47; + public static readonly PARAM = 48; + public static readonly RLIKE = 49; + public static readonly RP = 50; + public static readonly TRUE = 51; + public static readonly EQ = 52; + public static readonly CIEQ = 53; + public static readonly NEQ = 54; + public static readonly LT = 55; + public static readonly LTE = 56; + public static readonly GT = 57; + public static readonly GTE = 58; + public static readonly PLUS = 59; + public static readonly MINUS = 60; + public static readonly ASTERISK = 61; + public static readonly SLASH = 62; + public static readonly PERCENT = 63; public static readonly NAMED_OR_POSITIONAL_PARAM = 64; public static readonly OPENING_BRACKET = 65; public static readonly CLOSING_BRACKET = 66; @@ -131,23 +131,22 @@ export default class esql_parser extends parser_config { public static readonly SHOW_LINE_COMMENT = 101; public static readonly SHOW_MULTILINE_COMMENT = 102; public static readonly SHOW_WS = 103; - public static readonly COLON = 104; - public static readonly SETTING = 105; - public static readonly SETTING_LINE_COMMENT = 106; - public static readonly SETTTING_MULTILINE_COMMENT = 107; - public static readonly SETTING_WS = 108; - public static readonly LOOKUP_LINE_COMMENT = 109; - public static readonly LOOKUP_MULTILINE_COMMENT = 110; - public static readonly LOOKUP_WS = 111; - public static readonly LOOKUP_FIELD_LINE_COMMENT = 112; - public static readonly LOOKUP_FIELD_MULTILINE_COMMENT = 113; - public static readonly LOOKUP_FIELD_WS = 114; - public static readonly METRICS_LINE_COMMENT = 115; - public static readonly METRICS_MULTILINE_COMMENT = 116; - public static readonly METRICS_WS = 117; - public static readonly CLOSING_METRICS_LINE_COMMENT = 118; - public static readonly CLOSING_METRICS_MULTILINE_COMMENT = 119; - public static readonly CLOSING_METRICS_WS = 120; + public static readonly SETTING = 104; + public static readonly SETTING_LINE_COMMENT = 105; + public static readonly SETTTING_MULTILINE_COMMENT = 106; + public static readonly SETTING_WS = 107; + public static readonly LOOKUP_LINE_COMMENT = 108; + public static readonly LOOKUP_MULTILINE_COMMENT = 109; + public static readonly LOOKUP_WS = 110; + public static readonly LOOKUP_FIELD_LINE_COMMENT = 111; + public static readonly LOOKUP_FIELD_MULTILINE_COMMENT = 112; + public static readonly LOOKUP_FIELD_WS = 113; + public static readonly METRICS_LINE_COMMENT = 114; + public static readonly METRICS_MULTILINE_COMMENT = 115; + public static readonly METRICS_WS = 116; + public static readonly CLOSING_METRICS_LINE_COMMENT = 117; + public static readonly CLOSING_METRICS_MULTILINE_COMMENT = 118; + public static readonly CLOSING_METRICS_WS = 119; public static override readonly EOF = Token.EOF; public static readonly RULE_singleStatement = 0; public static readonly RULE_query = 1; @@ -224,26 +223,26 @@ export default class esql_parser extends parser_config { null, null, null, null, null, null, - "'|'", null, + "':'", "'|'", null, null, - "'by'", "'and'", - "'asc'", "'='", - "'::'", "','", - "'desc'", "'.'", - "'false'", "'first'", - "'in'", "'is'", - "'last'", "'like'", - "'('", "'not'", - "'null'", "'nulls'", - "'or'", "'?'", - "'rlike'", "')'", - "'true'", "'=='", - "'=~'", "'!='", - "'<'", "'<='", - "'>'", "'>='", - "'+'", "'-'", - "'*'", "'/'", - "'%'", "'match'", + null, "'by'", + "'and'", "'asc'", + "'='", "'::'", + "','", "'desc'", + "'.'", "'false'", + "'first'", "'in'", + "'is'", "'last'", + "'like'", "'('", + "'not'", "'null'", + "'nulls'", "'or'", + "'?'", "'rlike'", + "')'", "'true'", + "'=='", "'=~'", + "'!='", "'<'", + "'<='", "'>'", + "'>='", "'+'", + "'-'", "'*'", + "'/'", "'%'", null, null, "']'", null, null, null, @@ -262,9 +261,7 @@ export default class esql_parser extends parser_config { null, null, null, null, null, null, - "'info'", null, - null, null, - "':'" ]; + "'info'" ]; public static readonly symbolicNames: (string | null)[] = [ null, "DISSECT", "DROP", "ENRICH", "EVAL", "EXPLAIN", @@ -280,8 +277,8 @@ export default class esql_parser extends parser_config { "UNKNOWN_CMD", "LINE_COMMENT", "MULTILINE_COMMENT", - "WS", "PIPE", - "QUOTED_STRING", + "WS", "COLON", + "PIPE", "QUOTED_STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "AND", @@ -302,7 +299,7 @@ export default class esql_parser extends parser_config { "GTE", "PLUS", "MINUS", "ASTERISK", "SLASH", "PERCENT", - "MATCH", "NAMED_OR_POSITIONAL_PARAM", + "NAMED_OR_POSITIONAL_PARAM", "OPENING_BRACKET", "CLOSING_BRACKET", "UNQUOTED_IDENTIFIER", @@ -339,7 +336,7 @@ export default class esql_parser extends parser_config { "INFO", "SHOW_LINE_COMMENT", "SHOW_MULTILINE_COMMENT", "SHOW_WS", - "COLON", "SETTING", + "SETTING", "SETTING_LINE_COMMENT", "SETTTING_MULTILINE_COMMENT", "SETTING_WS", @@ -767,7 +764,7 @@ export default class esql_parser extends parser_config { this.state = 174; this._errHandler.sync(this); _la = this._input.LA(1); - if (_la===43) { + if (_la===44) { { this.state = 173; this.match(esql_parser.NOT); @@ -783,7 +780,7 @@ export default class esql_parser extends parser_config { this.state = 183; this._errHandler.sync(this); _la = this._input.LA(1); - while (_la===33) { + while (_la===34) { { { this.state = 179; @@ -812,7 +809,7 @@ export default class esql_parser extends parser_config { this.state = 191; this._errHandler.sync(this); _la = this._input.LA(1); - if (_la===43) { + if (_la===44) { { this.state = 190; this.match(esql_parser.NOT); @@ -921,7 +918,7 @@ export default class esql_parser extends parser_config { this.state = 212; this._errHandler.sync(this); _la = this._input.LA(1); - if (_la===43) { + if (_la===44) { { this.state = 211; this.match(esql_parser.NOT); @@ -942,7 +939,7 @@ export default class esql_parser extends parser_config { this.state = 219; this._errHandler.sync(this); _la = this._input.LA(1); - if (_la===43) { + if (_la===44) { { this.state = 218; this.match(esql_parser.NOT); @@ -979,11 +976,11 @@ export default class esql_parser extends parser_config { this.enterOuterAlt(localctx, 1); { this.state = 226; - this.valueExpression(); + localctx._fieldExp = this.qualifiedName(); this.state = 227; - this.match(esql_parser.MATCH); + this.match(esql_parser.COLON); this.state = 228; - localctx._queryString = this.string_(); + localctx._queryString = this.constant(); } } catch (re) { @@ -1085,7 +1082,7 @@ export default class esql_parser extends parser_config { this.state = 239; (localctx as ArithmeticUnaryContext)._operator = this._input.LT(1); _la = this._input.LA(1); - if(!(_la===58 || _la===59)) { + if(!(_la===59 || _la===60)) { (localctx as ArithmeticUnaryContext)._operator = this._errHandler.recoverInline(this); } else { @@ -1123,7 +1120,7 @@ export default class esql_parser extends parser_config { this.state = 244; (localctx as ArithmeticBinaryContext)._operator = this._input.LT(1); _la = this._input.LA(1); - if(!(((((_la - 60)) & ~0x1F) === 0 && ((1 << (_la - 60)) & 7) !== 0))) { + if(!(((((_la - 61)) & ~0x1F) === 0 && ((1 << (_la - 61)) & 7) !== 0))) { (localctx as ArithmeticBinaryContext)._operator = this._errHandler.recoverInline(this); } else { @@ -1146,7 +1143,7 @@ export default class esql_parser extends parser_config { this.state = 247; (localctx as ArithmeticBinaryContext)._operator = this._input.LT(1); _la = this._input.LA(1); - if(!(_la===58 || _la===59)) { + if(!(_la===59 || _la===60)) { (localctx as ArithmeticBinaryContext)._operator = this._errHandler.recoverInline(this); } else { @@ -1318,7 +1315,7 @@ export default class esql_parser extends parser_config { this.state = 280; this._errHandler.sync(this); _la = this._input.LA(1); - while (_la===33) { + while (_la===34) { { { this.state = 276; @@ -1358,23 +1355,10 @@ export default class esql_parser extends parser_config { let localctx: FunctionNameContext = new FunctionNameContext(this, this._ctx, this.state); this.enterRule(localctx, 24, esql_parser.RULE_functionName); try { - this.state = 289; - this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 20, this._ctx) ) { - case 1: - this.enterOuterAlt(localctx, 1); - { - this.state = 287; - this.match(esql_parser.MATCH); - } - break; - case 2: - this.enterOuterAlt(localctx, 2); - { - this.state = 288; - this.identifierOrParameter(); - } - break; + this.enterOuterAlt(localctx, 1); + { + this.state = 287; + this.identifierOrParameter(); } } catch (re) { @@ -1399,7 +1383,7 @@ export default class esql_parser extends parser_config { localctx = new ToDataTypeContext(this, localctx); this.enterOuterAlt(localctx, 1); { - this.state = 291; + this.state = 289; this.identifier(); } } @@ -1424,9 +1408,9 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 293; + this.state = 291; this.match(esql_parser.ROW); - this.state = 294; + this.state = 292; this.fields(); } } @@ -1452,25 +1436,25 @@ export default class esql_parser extends parser_config { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 296; + this.state = 294; this.field(); - this.state = 301; + this.state = 299; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 21, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 20, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 297; + this.state = 295; this.match(esql_parser.COMMA); - this.state = 298; + this.state = 296; this.field(); } } } - this.state = 303; + this.state = 301; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 21, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 20, this._ctx); } } } @@ -1495,19 +1479,19 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 307; + this.state = 305; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 22, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 21, this._ctx) ) { case 1: { - this.state = 304; + this.state = 302; this.qualifiedName(); - this.state = 305; + this.state = 303; this.match(esql_parser.ASSIGN); } break; } - this.state = 309; + this.state = 307; this.booleanExpression(0); } } @@ -1533,34 +1517,34 @@ export default class esql_parser extends parser_config { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 311; + this.state = 309; this.match(esql_parser.FROM); - this.state = 312; + this.state = 310; this.indexPattern(); - this.state = 317; + this.state = 315; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 23, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 22, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 313; + this.state = 311; this.match(esql_parser.COMMA); - this.state = 314; + this.state = 312; this.indexPattern(); } } } - this.state = 319; + this.state = 317; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 23, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 22, this._ctx); } - this.state = 321; + this.state = 319; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 24, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 23, this._ctx) ) { case 1: { - this.state = 320; + this.state = 318; this.metadata(); } break; @@ -1588,19 +1572,19 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 326; + this.state = 324; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 25, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 24, this._ctx) ) { case 1: { - this.state = 323; + this.state = 321; this.clusterString(); - this.state = 324; + this.state = 322; this.match(esql_parser.COLON); } break; } - this.state = 328; + this.state = 326; this.indexString(); } } @@ -1625,7 +1609,7 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 330; + this.state = 328; this.match(esql_parser.UNQUOTED_SOURCE); } } @@ -1651,9 +1635,9 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 332; + this.state = 330; _la = this._input.LA(1); - if(!(_la===25 || _la===76)) { + if(!(_la===26 || _la===76)) { this._errHandler.recoverInline(this); } else { @@ -1681,20 +1665,20 @@ export default class esql_parser extends parser_config { let localctx: MetadataContext = new MetadataContext(this, this._ctx, this.state); this.enterRule(localctx, 42, esql_parser.RULE_metadata); try { - this.state = 336; + this.state = 334; this._errHandler.sync(this); switch (this._input.LA(1)) { case 75: this.enterOuterAlt(localctx, 1); { - this.state = 334; + this.state = 332; this.metadataOption(); } break; case 65: this.enterOuterAlt(localctx, 2); { - this.state = 335; + this.state = 333; this.deprecated_metadata(); } break; @@ -1724,27 +1708,27 @@ export default class esql_parser extends parser_config { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 338; + this.state = 336; this.match(esql_parser.METADATA); - this.state = 339; + this.state = 337; this.match(esql_parser.UNQUOTED_SOURCE); - this.state = 344; + this.state = 342; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 27, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 26, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 340; + this.state = 338; this.match(esql_parser.COMMA); - this.state = 341; + this.state = 339; this.match(esql_parser.UNQUOTED_SOURCE); } } } - this.state = 346; + this.state = 344; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 27, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 26, this._ctx); } } } @@ -1769,11 +1753,11 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 347; + this.state = 345; this.match(esql_parser.OPENING_BRACKET); - this.state = 348; + this.state = 346; this.metadataOption(); - this.state = 349; + this.state = 347; this.match(esql_parser.CLOSING_BRACKET); } } @@ -1799,46 +1783,46 @@ export default class esql_parser extends parser_config { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 351; + this.state = 349; this.match(esql_parser.DEV_METRICS); - this.state = 352; + this.state = 350; this.indexPattern(); - this.state = 357; + this.state = 355; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 28, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 27, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 353; + this.state = 351; this.match(esql_parser.COMMA); - this.state = 354; + this.state = 352; this.indexPattern(); } } } - this.state = 359; + this.state = 357; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 28, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 27, this._ctx); } - this.state = 361; + this.state = 359; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 29, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 28, this._ctx) ) { case 1: { - this.state = 360; + this.state = 358; localctx._aggregates = this.aggFields(); } break; } - this.state = 365; + this.state = 363; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 30, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 29, this._ctx) ) { case 1: { - this.state = 363; + this.state = 361; this.match(esql_parser.BY); - this.state = 364; + this.state = 362; localctx._grouping = this.fields(); } break; @@ -1866,9 +1850,9 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 367; + this.state = 365; this.match(esql_parser.EVAL); - this.state = 368; + this.state = 366; this.fields(); } } @@ -1893,26 +1877,26 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 370; + this.state = 368; this.match(esql_parser.STATS); - this.state = 372; + this.state = 370; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 31, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 30, this._ctx) ) { case 1: { - this.state = 371; + this.state = 369; localctx._stats = this.aggFields(); } break; } - this.state = 376; + this.state = 374; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 32, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 31, this._ctx) ) { case 1: { - this.state = 374; + this.state = 372; this.match(esql_parser.BY); - this.state = 375; + this.state = 373; localctx._grouping = this.fields(); } break; @@ -1941,25 +1925,25 @@ export default class esql_parser extends parser_config { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 378; + this.state = 376; this.aggField(); - this.state = 383; + this.state = 381; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 33, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 32, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 379; + this.state = 377; this.match(esql_parser.COMMA); - this.state = 380; + this.state = 378; this.aggField(); } } } - this.state = 385; + this.state = 383; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 33, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 32, this._ctx); } } } @@ -1984,16 +1968,16 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 386; + this.state = 384; this.field(); - this.state = 389; + this.state = 387; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 34, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 33, this._ctx) ) { case 1: { - this.state = 387; + this.state = 385; this.match(esql_parser.WHERE); - this.state = 388; + this.state = 386; this.booleanExpression(0); } break; @@ -2022,25 +2006,25 @@ export default class esql_parser extends parser_config { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 391; + this.state = 389; this.identifierOrParameter(); - this.state = 396; + this.state = 394; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 35, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 34, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 392; + this.state = 390; this.match(esql_parser.DOT); - this.state = 393; + this.state = 391; this.identifierOrParameter(); } } } - this.state = 398; + this.state = 396; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 35, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 34, this._ctx); } } } @@ -2066,25 +2050,25 @@ export default class esql_parser extends parser_config { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 399; + this.state = 397; this.identifierPattern(); - this.state = 404; + this.state = 402; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 36, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 35, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 400; + this.state = 398; this.match(esql_parser.DOT); - this.state = 401; + this.state = 399; this.identifierPattern(); } } } - this.state = 406; + this.state = 404; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 36, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 35, this._ctx); } } } @@ -2110,25 +2094,25 @@ export default class esql_parser extends parser_config { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 407; + this.state = 405; this.qualifiedNamePattern(); - this.state = 412; + this.state = 410; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 37, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 36, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 408; + this.state = 406; this.match(esql_parser.COMMA); - this.state = 409; + this.state = 407; this.qualifiedNamePattern(); } } } - this.state = 414; + this.state = 412; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 37, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 36, this._ctx); } } } @@ -2154,7 +2138,7 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 415; + this.state = 413; _la = this._input.LA(1); if(!(_la===67 || _la===68)) { this._errHandler.recoverInline(this); @@ -2184,24 +2168,24 @@ export default class esql_parser extends parser_config { let localctx: IdentifierPatternContext = new IdentifierPatternContext(this, this._ctx, this.state); this.enterRule(localctx, 66, esql_parser.RULE_identifierPattern); try { - this.state = 420; + this.state = 418; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 38, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 37, this._ctx) ) { case 1: this.enterOuterAlt(localctx, 1); { - this.state = 417; + this.state = 415; this.match(esql_parser.ID_PATTERN); } break; case 2: this.enterOuterAlt(localctx, 2); { - this.state = 418; + this.state = 416; if (!(this.isDevVersion())) { throw this.createFailedPredicateException("this.isDevVersion()"); } - this.state = 419; + this.state = 417; this.parameter(); } break; @@ -2227,14 +2211,14 @@ export default class esql_parser extends parser_config { this.enterRule(localctx, 68, esql_parser.RULE_constant); let _la: number; try { - this.state = 464; + this.state = 462; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 42, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 41, this._ctx) ) { case 1: localctx = new NullLiteralContext(this, localctx); this.enterOuterAlt(localctx, 1); { - this.state = 422; + this.state = 420; this.match(esql_parser.NULL); } break; @@ -2242,9 +2226,9 @@ export default class esql_parser extends parser_config { localctx = new QualifiedIntegerLiteralContext(this, localctx); this.enterOuterAlt(localctx, 2); { - this.state = 423; + this.state = 421; this.integerValue(); - this.state = 424; + this.state = 422; this.match(esql_parser.UNQUOTED_IDENTIFIER); } break; @@ -2252,7 +2236,7 @@ export default class esql_parser extends parser_config { localctx = new DecimalLiteralContext(this, localctx); this.enterOuterAlt(localctx, 3); { - this.state = 426; + this.state = 424; this.decimalValue(); } break; @@ -2260,7 +2244,7 @@ export default class esql_parser extends parser_config { localctx = new IntegerLiteralContext(this, localctx); this.enterOuterAlt(localctx, 4); { - this.state = 427; + this.state = 425; this.integerValue(); } break; @@ -2268,7 +2252,7 @@ export default class esql_parser extends parser_config { localctx = new BooleanLiteralContext(this, localctx); this.enterOuterAlt(localctx, 5); { - this.state = 428; + this.state = 426; this.booleanValue(); } break; @@ -2276,7 +2260,7 @@ export default class esql_parser extends parser_config { localctx = new InputParameterContext(this, localctx); this.enterOuterAlt(localctx, 6); { - this.state = 429; + this.state = 427; this.parameter(); } break; @@ -2284,7 +2268,7 @@ export default class esql_parser extends parser_config { localctx = new StringLiteralContext(this, localctx); this.enterOuterAlt(localctx, 7); { - this.state = 430; + this.state = 428; this.string_(); } break; @@ -2292,27 +2276,27 @@ export default class esql_parser extends parser_config { localctx = new NumericArrayLiteralContext(this, localctx); this.enterOuterAlt(localctx, 8); { - this.state = 431; + this.state = 429; this.match(esql_parser.OPENING_BRACKET); - this.state = 432; + this.state = 430; this.numericValue(); - this.state = 437; + this.state = 435; this._errHandler.sync(this); _la = this._input.LA(1); - while (_la===33) { + while (_la===34) { { { - this.state = 433; + this.state = 431; this.match(esql_parser.COMMA); - this.state = 434; + this.state = 432; this.numericValue(); } } - this.state = 439; + this.state = 437; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 440; + this.state = 438; this.match(esql_parser.CLOSING_BRACKET); } break; @@ -2320,27 +2304,27 @@ export default class esql_parser extends parser_config { localctx = new BooleanArrayLiteralContext(this, localctx); this.enterOuterAlt(localctx, 9); { - this.state = 442; + this.state = 440; this.match(esql_parser.OPENING_BRACKET); - this.state = 443; + this.state = 441; this.booleanValue(); - this.state = 448; + this.state = 446; this._errHandler.sync(this); _la = this._input.LA(1); - while (_la===33) { + while (_la===34) { { { - this.state = 444; + this.state = 442; this.match(esql_parser.COMMA); - this.state = 445; + this.state = 443; this.booleanValue(); } } - this.state = 450; + this.state = 448; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 451; + this.state = 449; this.match(esql_parser.CLOSING_BRACKET); } break; @@ -2348,27 +2332,27 @@ export default class esql_parser extends parser_config { localctx = new StringArrayLiteralContext(this, localctx); this.enterOuterAlt(localctx, 10); { - this.state = 453; + this.state = 451; this.match(esql_parser.OPENING_BRACKET); - this.state = 454; + this.state = 452; this.string_(); - this.state = 459; + this.state = 457; this._errHandler.sync(this); _la = this._input.LA(1); - while (_la===33) { + while (_la===34) { { { - this.state = 455; + this.state = 453; this.match(esql_parser.COMMA); - this.state = 456; + this.state = 454; this.string_(); } } - this.state = 461; + this.state = 459; this._errHandler.sync(this); _la = this._input.LA(1); } - this.state = 462; + this.state = 460; this.match(esql_parser.CLOSING_BRACKET); } break; @@ -2393,14 +2377,14 @@ export default class esql_parser extends parser_config { let localctx: ParameterContext = new ParameterContext(this, this._ctx, this.state); this.enterRule(localctx, 70, esql_parser.RULE_parameter); try { - this.state = 468; + this.state = 466; this._errHandler.sync(this); switch (this._input.LA(1)) { - case 47: + case 48: localctx = new InputParamContext(this, localctx); this.enterOuterAlt(localctx, 1); { - this.state = 466; + this.state = 464; this.match(esql_parser.PARAM); } break; @@ -2408,7 +2392,7 @@ export default class esql_parser extends parser_config { localctx = new InputNamedOrPositionalParamContext(this, localctx); this.enterOuterAlt(localctx, 2); { - this.state = 467; + this.state = 465; this.match(esql_parser.NAMED_OR_POSITIONAL_PARAM); } break; @@ -2435,24 +2419,24 @@ export default class esql_parser extends parser_config { let localctx: IdentifierOrParameterContext = new IdentifierOrParameterContext(this, this._ctx, this.state); this.enterRule(localctx, 72, esql_parser.RULE_identifierOrParameter); try { - this.state = 473; + this.state = 471; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 44, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 43, this._ctx) ) { case 1: this.enterOuterAlt(localctx, 1); { - this.state = 470; + this.state = 468; this.identifier(); } break; case 2: this.enterOuterAlt(localctx, 2); { - this.state = 471; + this.state = 469; if (!(this.isDevVersion())) { throw this.createFailedPredicateException("this.isDevVersion()"); } - this.state = 472; + this.state = 470; this.parameter(); } break; @@ -2479,9 +2463,9 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 475; + this.state = 473; this.match(esql_parser.LIMIT); - this.state = 476; + this.state = 474; this.match(esql_parser.INTEGER_LITERAL); } } @@ -2507,27 +2491,27 @@ export default class esql_parser extends parser_config { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 478; + this.state = 476; this.match(esql_parser.SORT); - this.state = 479; + this.state = 477; this.orderExpression(); - this.state = 484; + this.state = 482; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 45, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 44, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 480; + this.state = 478; this.match(esql_parser.COMMA); - this.state = 481; + this.state = 479; this.orderExpression(); } } } - this.state = 486; + this.state = 484; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 45, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 44, this._ctx); } } } @@ -2553,17 +2537,17 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 487; + this.state = 485; this.booleanExpression(0); - this.state = 489; + this.state = 487; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 46, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 45, this._ctx) ) { case 1: { - this.state = 488; + this.state = 486; localctx._ordering = this._input.LT(1); _la = this._input.LA(1); - if(!(_la===30 || _la===34)) { + if(!(_la===31 || _la===35)) { localctx._ordering = this._errHandler.recoverInline(this); } else { @@ -2573,17 +2557,17 @@ export default class esql_parser extends parser_config { } break; } - this.state = 493; + this.state = 491; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 47, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 46, this._ctx) ) { case 1: { - this.state = 491; + this.state = 489; this.match(esql_parser.NULLS); - this.state = 492; + this.state = 490; localctx._nullOrdering = this._input.LT(1); _la = this._input.LA(1); - if(!(_la===37 || _la===40)) { + if(!(_la===38 || _la===41)) { localctx._nullOrdering = this._errHandler.recoverInline(this); } else { @@ -2616,9 +2600,9 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 495; + this.state = 493; this.match(esql_parser.KEEP); - this.state = 496; + this.state = 494; this.qualifiedNamePatterns(); } } @@ -2643,9 +2627,9 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 498; + this.state = 496; this.match(esql_parser.DROP); - this.state = 499; + this.state = 497; this.qualifiedNamePatterns(); } } @@ -2671,27 +2655,27 @@ export default class esql_parser extends parser_config { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 501; + this.state = 499; this.match(esql_parser.RENAME); - this.state = 502; + this.state = 500; this.renameClause(); - this.state = 507; + this.state = 505; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 48, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 47, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 503; + this.state = 501; this.match(esql_parser.COMMA); - this.state = 504; + this.state = 502; this.renameClause(); } } } - this.state = 509; + this.state = 507; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 48, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 47, this._ctx); } } } @@ -2716,11 +2700,11 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 510; + this.state = 508; localctx._oldName = this.qualifiedNamePattern(); - this.state = 511; + this.state = 509; this.match(esql_parser.AS); - this.state = 512; + this.state = 510; localctx._newName = this.qualifiedNamePattern(); } } @@ -2745,18 +2729,18 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 514; + this.state = 512; this.match(esql_parser.DISSECT); - this.state = 515; + this.state = 513; this.primaryExpression(0); - this.state = 516; + this.state = 514; this.string_(); - this.state = 518; + this.state = 516; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 49, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 48, this._ctx) ) { case 1: { - this.state = 517; + this.state = 515; this.commandOptions(); } break; @@ -2784,11 +2768,11 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 520; + this.state = 518; this.match(esql_parser.GROK); - this.state = 521; + this.state = 519; this.primaryExpression(0); - this.state = 522; + this.state = 520; this.string_(); } } @@ -2813,9 +2797,9 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 524; + this.state = 522; this.match(esql_parser.MV_EXPAND); - this.state = 525; + this.state = 523; this.qualifiedName(); } } @@ -2841,25 +2825,25 @@ export default class esql_parser extends parser_config { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 527; + this.state = 525; this.commandOption(); - this.state = 532; + this.state = 530; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 50, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 49, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 528; + this.state = 526; this.match(esql_parser.COMMA); - this.state = 529; + this.state = 527; this.commandOption(); } } } - this.state = 534; + this.state = 532; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 50, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 49, this._ctx); } } } @@ -2884,11 +2868,11 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 535; + this.state = 533; this.identifier(); - this.state = 536; + this.state = 534; this.match(esql_parser.ASSIGN); - this.state = 537; + this.state = 535; this.constant(); } } @@ -2914,9 +2898,9 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 539; + this.state = 537; _la = this._input.LA(1); - if(!(_la===36 || _la===50)) { + if(!(_la===37 || _la===51)) { this._errHandler.recoverInline(this); } else { @@ -2944,20 +2928,20 @@ export default class esql_parser extends parser_config { let localctx: NumericValueContext = new NumericValueContext(this, this._ctx, this.state); this.enterRule(localctx, 100, esql_parser.RULE_numericValue); try { - this.state = 543; + this.state = 541; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 51, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 50, this._ctx) ) { case 1: this.enterOuterAlt(localctx, 1); { - this.state = 541; + this.state = 539; this.decimalValue(); } break; case 2: this.enterOuterAlt(localctx, 2); { - this.state = 542; + this.state = 540; this.integerValue(); } break; @@ -2985,14 +2969,14 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 546; + this.state = 544; this._errHandler.sync(this); _la = this._input.LA(1); - if (_la===58 || _la===59) { + if (_la===59 || _la===60) { { - this.state = 545; + this.state = 543; _la = this._input.LA(1); - if(!(_la===58 || _la===59)) { + if(!(_la===59 || _la===60)) { this._errHandler.recoverInline(this); } else { @@ -3002,7 +2986,7 @@ export default class esql_parser extends parser_config { } } - this.state = 548; + this.state = 546; this.match(esql_parser.DECIMAL_LITERAL); } } @@ -3028,14 +3012,14 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 551; + this.state = 549; this._errHandler.sync(this); _la = this._input.LA(1); - if (_la===58 || _la===59) { + if (_la===59 || _la===60) { { - this.state = 550; + this.state = 548; _la = this._input.LA(1); - if(!(_la===58 || _la===59)) { + if(!(_la===59 || _la===60)) { this._errHandler.recoverInline(this); } else { @@ -3045,7 +3029,7 @@ export default class esql_parser extends parser_config { } } - this.state = 553; + this.state = 551; this.match(esql_parser.INTEGER_LITERAL); } } @@ -3070,7 +3054,7 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 555; + this.state = 553; this.match(esql_parser.QUOTED_STRING); } } @@ -3096,9 +3080,9 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 557; + this.state = 555; _la = this._input.LA(1); - if(!(((((_la - 51)) & ~0x1F) === 0 && ((1 << (_la - 51)) & 125) !== 0))) { + if(!(((((_la - 52)) & ~0x1F) === 0 && ((1 << (_la - 52)) & 125) !== 0))) { this._errHandler.recoverInline(this); } else { @@ -3128,9 +3112,9 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 559; + this.state = 557; this.match(esql_parser.EXPLAIN); - this.state = 560; + this.state = 558; this.subqueryExpression(); } } @@ -3155,11 +3139,11 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 562; + this.state = 560; this.match(esql_parser.OPENING_BRACKET); - this.state = 563; + this.state = 561; this.query(0); - this.state = 564; + this.state = 562; this.match(esql_parser.CLOSING_BRACKET); } } @@ -3185,9 +3169,9 @@ export default class esql_parser extends parser_config { localctx = new ShowInfoContext(this, localctx); this.enterOuterAlt(localctx, 1); { - this.state = 566; + this.state = 564; this.match(esql_parser.SHOW); - this.state = 567; + this.state = 565; this.match(esql_parser.INFO); } } @@ -3213,48 +3197,48 @@ export default class esql_parser extends parser_config { let _alt: number; this.enterOuterAlt(localctx, 1); { - this.state = 569; + this.state = 567; this.match(esql_parser.ENRICH); - this.state = 570; + this.state = 568; localctx._policyName = this.match(esql_parser.ENRICH_POLICY_NAME); - this.state = 573; + this.state = 571; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 54, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 53, this._ctx) ) { case 1: { - this.state = 571; + this.state = 569; this.match(esql_parser.ON); - this.state = 572; + this.state = 570; localctx._matchField = this.qualifiedNamePattern(); } break; } - this.state = 584; + this.state = 582; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 56, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 55, this._ctx) ) { case 1: { - this.state = 575; + this.state = 573; this.match(esql_parser.WITH); - this.state = 576; + this.state = 574; this.enrichWithClause(); - this.state = 581; + this.state = 579; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 55, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 54, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 577; + this.state = 575; this.match(esql_parser.COMMA); - this.state = 578; + this.state = 576; this.enrichWithClause(); } } } - this.state = 583; + this.state = 581; this._errHandler.sync(this); - _alt = this._interp.adaptivePredict(this._input, 55, this._ctx); + _alt = this._interp.adaptivePredict(this._input, 54, this._ctx); } } break; @@ -3282,19 +3266,19 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 589; + this.state = 587; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 57, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 56, this._ctx) ) { case 1: { - this.state = 586; + this.state = 584; localctx._newName = this.qualifiedNamePattern(); - this.state = 587; + this.state = 585; this.match(esql_parser.ASSIGN); } break; } - this.state = 591; + this.state = 589; localctx._enrichField = this.qualifiedNamePattern(); } } @@ -3319,13 +3303,13 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 593; + this.state = 591; this.match(esql_parser.DEV_LOOKUP); - this.state = 594; + this.state = 592; localctx._tableName = this.indexPattern(); - this.state = 595; + this.state = 593; this.match(esql_parser.ON); - this.state = 596; + this.state = 594; localctx._matchFields = this.qualifiedNamePatterns(); } } @@ -3350,18 +3334,18 @@ export default class esql_parser extends parser_config { try { this.enterOuterAlt(localctx, 1); { - this.state = 598; + this.state = 596; this.match(esql_parser.DEV_INLINESTATS); - this.state = 599; + this.state = 597; localctx._stats = this.aggFields(); - this.state = 602; + this.state = 600; this._errHandler.sync(this); - switch ( this._interp.adaptivePredict(this._input, 58, this._ctx) ) { + switch ( this._interp.adaptivePredict(this._input, 57, this._ctx) ) { case 1: { - this.state = 600; + this.state = 598; this.match(esql_parser.BY); - this.state = 601; + this.state = 599; localctx._grouping = this.fields(); } break; @@ -3469,7 +3453,7 @@ export default class esql_parser extends parser_config { return true; } - public static readonly _serializedATN: number[] = [4,1,120,605,2,0,7,0, + public static readonly _serializedATN: number[] = [4,1,119,603,2,0,7,0, 2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7,6,2,7,7,7,2,8,7,8,2,9,7,9, 2,10,7,10,2,11,7,11,2,12,7,12,2,13,7,13,2,14,7,14,2,15,7,15,2,16,7,16,2, 17,7,17,2,18,7,18,2,19,7,19,2,20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24, @@ -3489,184 +3473,183 @@ export default class esql_parser extends parser_config { 9,1,9,5,9,250,8,9,10,9,12,9,253,9,9,1,10,1,10,1,10,1,10,1,10,1,10,1,10, 1,10,3,10,263,8,10,1,10,1,10,1,10,5,10,268,8,10,10,10,12,10,271,9,10,1, 11,1,11,1,11,1,11,1,11,1,11,5,11,279,8,11,10,11,12,11,282,9,11,3,11,284, - 8,11,1,11,1,11,1,12,1,12,3,12,290,8,12,1,13,1,13,1,14,1,14,1,14,1,15,1, - 15,1,15,5,15,300,8,15,10,15,12,15,303,9,15,1,16,1,16,1,16,3,16,308,8,16, - 1,16,1,16,1,17,1,17,1,17,1,17,5,17,316,8,17,10,17,12,17,319,9,17,1,17,3, - 17,322,8,17,1,18,1,18,1,18,3,18,327,8,18,1,18,1,18,1,19,1,19,1,20,1,20, - 1,21,1,21,3,21,337,8,21,1,22,1,22,1,22,1,22,5,22,343,8,22,10,22,12,22,346, - 9,22,1,23,1,23,1,23,1,23,1,24,1,24,1,24,1,24,5,24,356,8,24,10,24,12,24, - 359,9,24,1,24,3,24,362,8,24,1,24,1,24,3,24,366,8,24,1,25,1,25,1,25,1,26, - 1,26,3,26,373,8,26,1,26,1,26,3,26,377,8,26,1,27,1,27,1,27,5,27,382,8,27, - 10,27,12,27,385,9,27,1,28,1,28,1,28,3,28,390,8,28,1,29,1,29,1,29,5,29,395, - 8,29,10,29,12,29,398,9,29,1,30,1,30,1,30,5,30,403,8,30,10,30,12,30,406, - 9,30,1,31,1,31,1,31,5,31,411,8,31,10,31,12,31,414,9,31,1,32,1,32,1,33,1, - 33,1,33,3,33,421,8,33,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34, - 1,34,1,34,1,34,5,34,436,8,34,10,34,12,34,439,9,34,1,34,1,34,1,34,1,34,1, - 34,1,34,5,34,447,8,34,10,34,12,34,450,9,34,1,34,1,34,1,34,1,34,1,34,1,34, - 5,34,458,8,34,10,34,12,34,461,9,34,1,34,1,34,3,34,465,8,34,1,35,1,35,3, - 35,469,8,35,1,36,1,36,1,36,3,36,474,8,36,1,37,1,37,1,37,1,38,1,38,1,38, - 1,38,5,38,483,8,38,10,38,12,38,486,9,38,1,39,1,39,3,39,490,8,39,1,39,1, - 39,3,39,494,8,39,1,40,1,40,1,40,1,41,1,41,1,41,1,42,1,42,1,42,1,42,5,42, - 506,8,42,10,42,12,42,509,9,42,1,43,1,43,1,43,1,43,1,44,1,44,1,44,1,44,3, - 44,519,8,44,1,45,1,45,1,45,1,45,1,46,1,46,1,46,1,47,1,47,1,47,5,47,531, - 8,47,10,47,12,47,534,9,47,1,48,1,48,1,48,1,48,1,49,1,49,1,50,1,50,3,50, - 544,8,50,1,51,3,51,547,8,51,1,51,1,51,1,52,3,52,552,8,52,1,52,1,52,1,53, - 1,53,1,54,1,54,1,55,1,55,1,55,1,56,1,56,1,56,1,56,1,57,1,57,1,57,1,58,1, - 58,1,58,1,58,3,58,574,8,58,1,58,1,58,1,58,1,58,5,58,580,8,58,10,58,12,58, - 583,9,58,3,58,585,8,58,1,59,1,59,1,59,3,59,590,8,59,1,59,1,59,1,60,1,60, - 1,60,1,60,1,60,1,61,1,61,1,61,1,61,3,61,603,8,61,1,61,0,4,2,10,18,20,62, - 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50, - 52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98, - 100,102,104,106,108,110,112,114,116,118,120,122,0,8,1,0,58,59,1,0,60,62, - 2,0,25,25,76,76,1,0,67,68,2,0,30,30,34,34,2,0,37,37,40,40,2,0,36,36,50, - 50,2,0,51,51,53,57,631,0,124,1,0,0,0,2,127,1,0,0,0,4,144,1,0,0,0,6,162, - 1,0,0,0,8,164,1,0,0,0,10,197,1,0,0,0,12,224,1,0,0,0,14,226,1,0,0,0,16,235, - 1,0,0,0,18,241,1,0,0,0,20,262,1,0,0,0,22,272,1,0,0,0,24,289,1,0,0,0,26, - 291,1,0,0,0,28,293,1,0,0,0,30,296,1,0,0,0,32,307,1,0,0,0,34,311,1,0,0,0, - 36,326,1,0,0,0,38,330,1,0,0,0,40,332,1,0,0,0,42,336,1,0,0,0,44,338,1,0, - 0,0,46,347,1,0,0,0,48,351,1,0,0,0,50,367,1,0,0,0,52,370,1,0,0,0,54,378, - 1,0,0,0,56,386,1,0,0,0,58,391,1,0,0,0,60,399,1,0,0,0,62,407,1,0,0,0,64, - 415,1,0,0,0,66,420,1,0,0,0,68,464,1,0,0,0,70,468,1,0,0,0,72,473,1,0,0,0, - 74,475,1,0,0,0,76,478,1,0,0,0,78,487,1,0,0,0,80,495,1,0,0,0,82,498,1,0, - 0,0,84,501,1,0,0,0,86,510,1,0,0,0,88,514,1,0,0,0,90,520,1,0,0,0,92,524, - 1,0,0,0,94,527,1,0,0,0,96,535,1,0,0,0,98,539,1,0,0,0,100,543,1,0,0,0,102, - 546,1,0,0,0,104,551,1,0,0,0,106,555,1,0,0,0,108,557,1,0,0,0,110,559,1,0, - 0,0,112,562,1,0,0,0,114,566,1,0,0,0,116,569,1,0,0,0,118,589,1,0,0,0,120, - 593,1,0,0,0,122,598,1,0,0,0,124,125,3,2,1,0,125,126,5,0,0,1,126,1,1,0,0, - 0,127,128,6,1,-1,0,128,129,3,4,2,0,129,135,1,0,0,0,130,131,10,1,0,0,131, - 132,5,24,0,0,132,134,3,6,3,0,133,130,1,0,0,0,134,137,1,0,0,0,135,133,1, - 0,0,0,135,136,1,0,0,0,136,3,1,0,0,0,137,135,1,0,0,0,138,145,3,110,55,0, - 139,145,3,34,17,0,140,145,3,28,14,0,141,145,3,114,57,0,142,143,4,2,1,0, - 143,145,3,48,24,0,144,138,1,0,0,0,144,139,1,0,0,0,144,140,1,0,0,0,144,141, - 1,0,0,0,144,142,1,0,0,0,145,5,1,0,0,0,146,163,3,50,25,0,147,163,3,8,4,0, - 148,163,3,80,40,0,149,163,3,74,37,0,150,163,3,52,26,0,151,163,3,76,38,0, - 152,163,3,82,41,0,153,163,3,84,42,0,154,163,3,88,44,0,155,163,3,90,45,0, - 156,163,3,116,58,0,157,163,3,92,46,0,158,159,4,3,2,0,159,163,3,122,61,0, - 160,161,4,3,3,0,161,163,3,120,60,0,162,146,1,0,0,0,162,147,1,0,0,0,162, - 148,1,0,0,0,162,149,1,0,0,0,162,150,1,0,0,0,162,151,1,0,0,0,162,152,1,0, - 0,0,162,153,1,0,0,0,162,154,1,0,0,0,162,155,1,0,0,0,162,156,1,0,0,0,162, - 157,1,0,0,0,162,158,1,0,0,0,162,160,1,0,0,0,163,7,1,0,0,0,164,165,5,16, - 0,0,165,166,3,10,5,0,166,9,1,0,0,0,167,168,6,5,-1,0,168,169,5,43,0,0,169, - 198,3,10,5,8,170,198,3,16,8,0,171,198,3,12,6,0,172,174,3,16,8,0,173,175, - 5,43,0,0,174,173,1,0,0,0,174,175,1,0,0,0,175,176,1,0,0,0,176,177,5,38,0, - 0,177,178,5,42,0,0,178,183,3,16,8,0,179,180,5,33,0,0,180,182,3,16,8,0,181, - 179,1,0,0,0,182,185,1,0,0,0,183,181,1,0,0,0,183,184,1,0,0,0,184,186,1,0, - 0,0,185,183,1,0,0,0,186,187,5,49,0,0,187,198,1,0,0,0,188,189,3,16,8,0,189, - 191,5,39,0,0,190,192,5,43,0,0,191,190,1,0,0,0,191,192,1,0,0,0,192,193,1, - 0,0,0,193,194,5,44,0,0,194,198,1,0,0,0,195,196,4,5,4,0,196,198,3,14,7,0, - 197,167,1,0,0,0,197,170,1,0,0,0,197,171,1,0,0,0,197,172,1,0,0,0,197,188, - 1,0,0,0,197,195,1,0,0,0,198,207,1,0,0,0,199,200,10,5,0,0,200,201,5,29,0, - 0,201,206,3,10,5,6,202,203,10,4,0,0,203,204,5,46,0,0,204,206,3,10,5,5,205, - 199,1,0,0,0,205,202,1,0,0,0,206,209,1,0,0,0,207,205,1,0,0,0,207,208,1,0, - 0,0,208,11,1,0,0,0,209,207,1,0,0,0,210,212,3,16,8,0,211,213,5,43,0,0,212, - 211,1,0,0,0,212,213,1,0,0,0,213,214,1,0,0,0,214,215,5,41,0,0,215,216,3, - 106,53,0,216,225,1,0,0,0,217,219,3,16,8,0,218,220,5,43,0,0,219,218,1,0, - 0,0,219,220,1,0,0,0,220,221,1,0,0,0,221,222,5,48,0,0,222,223,3,106,53,0, - 223,225,1,0,0,0,224,210,1,0,0,0,224,217,1,0,0,0,225,13,1,0,0,0,226,227, - 3,16,8,0,227,228,5,63,0,0,228,229,3,106,53,0,229,15,1,0,0,0,230,236,3,18, - 9,0,231,232,3,18,9,0,232,233,3,108,54,0,233,234,3,18,9,0,234,236,1,0,0, - 0,235,230,1,0,0,0,235,231,1,0,0,0,236,17,1,0,0,0,237,238,6,9,-1,0,238,242, - 3,20,10,0,239,240,7,0,0,0,240,242,3,18,9,3,241,237,1,0,0,0,241,239,1,0, - 0,0,242,251,1,0,0,0,243,244,10,2,0,0,244,245,7,1,0,0,245,250,3,18,9,3,246, - 247,10,1,0,0,247,248,7,0,0,0,248,250,3,18,9,2,249,243,1,0,0,0,249,246,1, - 0,0,0,250,253,1,0,0,0,251,249,1,0,0,0,251,252,1,0,0,0,252,19,1,0,0,0,253, - 251,1,0,0,0,254,255,6,10,-1,0,255,263,3,68,34,0,256,263,3,58,29,0,257,263, - 3,22,11,0,258,259,5,42,0,0,259,260,3,10,5,0,260,261,5,49,0,0,261,263,1, - 0,0,0,262,254,1,0,0,0,262,256,1,0,0,0,262,257,1,0,0,0,262,258,1,0,0,0,263, - 269,1,0,0,0,264,265,10,1,0,0,265,266,5,32,0,0,266,268,3,26,13,0,267,264, - 1,0,0,0,268,271,1,0,0,0,269,267,1,0,0,0,269,270,1,0,0,0,270,21,1,0,0,0, - 271,269,1,0,0,0,272,273,3,24,12,0,273,283,5,42,0,0,274,284,5,60,0,0,275, - 280,3,10,5,0,276,277,5,33,0,0,277,279,3,10,5,0,278,276,1,0,0,0,279,282, - 1,0,0,0,280,278,1,0,0,0,280,281,1,0,0,0,281,284,1,0,0,0,282,280,1,0,0,0, - 283,274,1,0,0,0,283,275,1,0,0,0,283,284,1,0,0,0,284,285,1,0,0,0,285,286, - 5,49,0,0,286,23,1,0,0,0,287,290,5,63,0,0,288,290,3,72,36,0,289,287,1,0, - 0,0,289,288,1,0,0,0,290,25,1,0,0,0,291,292,3,64,32,0,292,27,1,0,0,0,293, - 294,5,12,0,0,294,295,3,30,15,0,295,29,1,0,0,0,296,301,3,32,16,0,297,298, - 5,33,0,0,298,300,3,32,16,0,299,297,1,0,0,0,300,303,1,0,0,0,301,299,1,0, - 0,0,301,302,1,0,0,0,302,31,1,0,0,0,303,301,1,0,0,0,304,305,3,58,29,0,305, - 306,5,31,0,0,306,308,1,0,0,0,307,304,1,0,0,0,307,308,1,0,0,0,308,309,1, - 0,0,0,309,310,3,10,5,0,310,33,1,0,0,0,311,312,5,6,0,0,312,317,3,36,18,0, - 313,314,5,33,0,0,314,316,3,36,18,0,315,313,1,0,0,0,316,319,1,0,0,0,317, - 315,1,0,0,0,317,318,1,0,0,0,318,321,1,0,0,0,319,317,1,0,0,0,320,322,3,42, - 21,0,321,320,1,0,0,0,321,322,1,0,0,0,322,35,1,0,0,0,323,324,3,38,19,0,324, - 325,5,104,0,0,325,327,1,0,0,0,326,323,1,0,0,0,326,327,1,0,0,0,327,328,1, - 0,0,0,328,329,3,40,20,0,329,37,1,0,0,0,330,331,5,76,0,0,331,39,1,0,0,0, - 332,333,7,2,0,0,333,41,1,0,0,0,334,337,3,44,22,0,335,337,3,46,23,0,336, - 334,1,0,0,0,336,335,1,0,0,0,337,43,1,0,0,0,338,339,5,75,0,0,339,344,5,76, - 0,0,340,341,5,33,0,0,341,343,5,76,0,0,342,340,1,0,0,0,343,346,1,0,0,0,344, - 342,1,0,0,0,344,345,1,0,0,0,345,45,1,0,0,0,346,344,1,0,0,0,347,348,5,65, - 0,0,348,349,3,44,22,0,349,350,5,66,0,0,350,47,1,0,0,0,351,352,5,19,0,0, - 352,357,3,36,18,0,353,354,5,33,0,0,354,356,3,36,18,0,355,353,1,0,0,0,356, - 359,1,0,0,0,357,355,1,0,0,0,357,358,1,0,0,0,358,361,1,0,0,0,359,357,1,0, - 0,0,360,362,3,54,27,0,361,360,1,0,0,0,361,362,1,0,0,0,362,365,1,0,0,0,363, - 364,5,28,0,0,364,366,3,30,15,0,365,363,1,0,0,0,365,366,1,0,0,0,366,49,1, - 0,0,0,367,368,5,4,0,0,368,369,3,30,15,0,369,51,1,0,0,0,370,372,5,15,0,0, - 371,373,3,54,27,0,372,371,1,0,0,0,372,373,1,0,0,0,373,376,1,0,0,0,374,375, - 5,28,0,0,375,377,3,30,15,0,376,374,1,0,0,0,376,377,1,0,0,0,377,53,1,0,0, - 0,378,383,3,56,28,0,379,380,5,33,0,0,380,382,3,56,28,0,381,379,1,0,0,0, - 382,385,1,0,0,0,383,381,1,0,0,0,383,384,1,0,0,0,384,55,1,0,0,0,385,383, - 1,0,0,0,386,389,3,32,16,0,387,388,5,16,0,0,388,390,3,10,5,0,389,387,1,0, - 0,0,389,390,1,0,0,0,390,57,1,0,0,0,391,396,3,72,36,0,392,393,5,35,0,0,393, - 395,3,72,36,0,394,392,1,0,0,0,395,398,1,0,0,0,396,394,1,0,0,0,396,397,1, - 0,0,0,397,59,1,0,0,0,398,396,1,0,0,0,399,404,3,66,33,0,400,401,5,35,0,0, - 401,403,3,66,33,0,402,400,1,0,0,0,403,406,1,0,0,0,404,402,1,0,0,0,404,405, - 1,0,0,0,405,61,1,0,0,0,406,404,1,0,0,0,407,412,3,60,30,0,408,409,5,33,0, - 0,409,411,3,60,30,0,410,408,1,0,0,0,411,414,1,0,0,0,412,410,1,0,0,0,412, - 413,1,0,0,0,413,63,1,0,0,0,414,412,1,0,0,0,415,416,7,3,0,0,416,65,1,0,0, - 0,417,421,5,80,0,0,418,419,4,33,10,0,419,421,3,70,35,0,420,417,1,0,0,0, - 420,418,1,0,0,0,421,67,1,0,0,0,422,465,5,44,0,0,423,424,3,104,52,0,424, - 425,5,67,0,0,425,465,1,0,0,0,426,465,3,102,51,0,427,465,3,104,52,0,428, - 465,3,98,49,0,429,465,3,70,35,0,430,465,3,106,53,0,431,432,5,65,0,0,432, - 437,3,100,50,0,433,434,5,33,0,0,434,436,3,100,50,0,435,433,1,0,0,0,436, - 439,1,0,0,0,437,435,1,0,0,0,437,438,1,0,0,0,438,440,1,0,0,0,439,437,1,0, - 0,0,440,441,5,66,0,0,441,465,1,0,0,0,442,443,5,65,0,0,443,448,3,98,49,0, - 444,445,5,33,0,0,445,447,3,98,49,0,446,444,1,0,0,0,447,450,1,0,0,0,448, - 446,1,0,0,0,448,449,1,0,0,0,449,451,1,0,0,0,450,448,1,0,0,0,451,452,5,66, - 0,0,452,465,1,0,0,0,453,454,5,65,0,0,454,459,3,106,53,0,455,456,5,33,0, - 0,456,458,3,106,53,0,457,455,1,0,0,0,458,461,1,0,0,0,459,457,1,0,0,0,459, - 460,1,0,0,0,460,462,1,0,0,0,461,459,1,0,0,0,462,463,5,66,0,0,463,465,1, - 0,0,0,464,422,1,0,0,0,464,423,1,0,0,0,464,426,1,0,0,0,464,427,1,0,0,0,464, - 428,1,0,0,0,464,429,1,0,0,0,464,430,1,0,0,0,464,431,1,0,0,0,464,442,1,0, - 0,0,464,453,1,0,0,0,465,69,1,0,0,0,466,469,5,47,0,0,467,469,5,64,0,0,468, - 466,1,0,0,0,468,467,1,0,0,0,469,71,1,0,0,0,470,474,3,64,32,0,471,472,4, - 36,11,0,472,474,3,70,35,0,473,470,1,0,0,0,473,471,1,0,0,0,474,73,1,0,0, - 0,475,476,5,9,0,0,476,477,5,26,0,0,477,75,1,0,0,0,478,479,5,14,0,0,479, - 484,3,78,39,0,480,481,5,33,0,0,481,483,3,78,39,0,482,480,1,0,0,0,483,486, - 1,0,0,0,484,482,1,0,0,0,484,485,1,0,0,0,485,77,1,0,0,0,486,484,1,0,0,0, - 487,489,3,10,5,0,488,490,7,4,0,0,489,488,1,0,0,0,489,490,1,0,0,0,490,493, - 1,0,0,0,491,492,5,45,0,0,492,494,7,5,0,0,493,491,1,0,0,0,493,494,1,0,0, - 0,494,79,1,0,0,0,495,496,5,8,0,0,496,497,3,62,31,0,497,81,1,0,0,0,498,499, - 5,2,0,0,499,500,3,62,31,0,500,83,1,0,0,0,501,502,5,11,0,0,502,507,3,86, - 43,0,503,504,5,33,0,0,504,506,3,86,43,0,505,503,1,0,0,0,506,509,1,0,0,0, - 507,505,1,0,0,0,507,508,1,0,0,0,508,85,1,0,0,0,509,507,1,0,0,0,510,511, - 3,60,30,0,511,512,5,84,0,0,512,513,3,60,30,0,513,87,1,0,0,0,514,515,5,1, - 0,0,515,516,3,20,10,0,516,518,3,106,53,0,517,519,3,94,47,0,518,517,1,0, - 0,0,518,519,1,0,0,0,519,89,1,0,0,0,520,521,5,7,0,0,521,522,3,20,10,0,522, - 523,3,106,53,0,523,91,1,0,0,0,524,525,5,10,0,0,525,526,3,58,29,0,526,93, - 1,0,0,0,527,532,3,96,48,0,528,529,5,33,0,0,529,531,3,96,48,0,530,528,1, - 0,0,0,531,534,1,0,0,0,532,530,1,0,0,0,532,533,1,0,0,0,533,95,1,0,0,0,534, - 532,1,0,0,0,535,536,3,64,32,0,536,537,5,31,0,0,537,538,3,68,34,0,538,97, - 1,0,0,0,539,540,7,6,0,0,540,99,1,0,0,0,541,544,3,102,51,0,542,544,3,104, - 52,0,543,541,1,0,0,0,543,542,1,0,0,0,544,101,1,0,0,0,545,547,7,0,0,0,546, - 545,1,0,0,0,546,547,1,0,0,0,547,548,1,0,0,0,548,549,5,27,0,0,549,103,1, - 0,0,0,550,552,7,0,0,0,551,550,1,0,0,0,551,552,1,0,0,0,552,553,1,0,0,0,553, - 554,5,26,0,0,554,105,1,0,0,0,555,556,5,25,0,0,556,107,1,0,0,0,557,558,7, - 7,0,0,558,109,1,0,0,0,559,560,5,5,0,0,560,561,3,112,56,0,561,111,1,0,0, - 0,562,563,5,65,0,0,563,564,3,2,1,0,564,565,5,66,0,0,565,113,1,0,0,0,566, - 567,5,13,0,0,567,568,5,100,0,0,568,115,1,0,0,0,569,570,5,3,0,0,570,573, - 5,90,0,0,571,572,5,88,0,0,572,574,3,60,30,0,573,571,1,0,0,0,573,574,1,0, - 0,0,574,584,1,0,0,0,575,576,5,89,0,0,576,581,3,118,59,0,577,578,5,33,0, - 0,578,580,3,118,59,0,579,577,1,0,0,0,580,583,1,0,0,0,581,579,1,0,0,0,581, - 582,1,0,0,0,582,585,1,0,0,0,583,581,1,0,0,0,584,575,1,0,0,0,584,585,1,0, - 0,0,585,117,1,0,0,0,586,587,3,60,30,0,587,588,5,31,0,0,588,590,1,0,0,0, - 589,586,1,0,0,0,589,590,1,0,0,0,590,591,1,0,0,0,591,592,3,60,30,0,592,119, - 1,0,0,0,593,594,5,18,0,0,594,595,3,36,18,0,595,596,5,88,0,0,596,597,3,62, - 31,0,597,121,1,0,0,0,598,599,5,17,0,0,599,602,3,54,27,0,600,601,5,28,0, - 0,601,603,3,30,15,0,602,600,1,0,0,0,602,603,1,0,0,0,603,123,1,0,0,0,59, + 8,11,1,11,1,11,1,12,1,12,1,13,1,13,1,14,1,14,1,14,1,15,1,15,1,15,5,15,298, + 8,15,10,15,12,15,301,9,15,1,16,1,16,1,16,3,16,306,8,16,1,16,1,16,1,17,1, + 17,1,17,1,17,5,17,314,8,17,10,17,12,17,317,9,17,1,17,3,17,320,8,17,1,18, + 1,18,1,18,3,18,325,8,18,1,18,1,18,1,19,1,19,1,20,1,20,1,21,1,21,3,21,335, + 8,21,1,22,1,22,1,22,1,22,5,22,341,8,22,10,22,12,22,344,9,22,1,23,1,23,1, + 23,1,23,1,24,1,24,1,24,1,24,5,24,354,8,24,10,24,12,24,357,9,24,1,24,3,24, + 360,8,24,1,24,1,24,3,24,364,8,24,1,25,1,25,1,25,1,26,1,26,3,26,371,8,26, + 1,26,1,26,3,26,375,8,26,1,27,1,27,1,27,5,27,380,8,27,10,27,12,27,383,9, + 27,1,28,1,28,1,28,3,28,388,8,28,1,29,1,29,1,29,5,29,393,8,29,10,29,12,29, + 396,9,29,1,30,1,30,1,30,5,30,401,8,30,10,30,12,30,404,9,30,1,31,1,31,1, + 31,5,31,409,8,31,10,31,12,31,412,9,31,1,32,1,32,1,33,1,33,1,33,3,33,419, + 8,33,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34,5, + 34,434,8,34,10,34,12,34,437,9,34,1,34,1,34,1,34,1,34,1,34,1,34,5,34,445, + 8,34,10,34,12,34,448,9,34,1,34,1,34,1,34,1,34,1,34,1,34,5,34,456,8,34,10, + 34,12,34,459,9,34,1,34,1,34,3,34,463,8,34,1,35,1,35,3,35,467,8,35,1,36, + 1,36,1,36,3,36,472,8,36,1,37,1,37,1,37,1,38,1,38,1,38,1,38,5,38,481,8,38, + 10,38,12,38,484,9,38,1,39,1,39,3,39,488,8,39,1,39,1,39,3,39,492,8,39,1, + 40,1,40,1,40,1,41,1,41,1,41,1,42,1,42,1,42,1,42,5,42,504,8,42,10,42,12, + 42,507,9,42,1,43,1,43,1,43,1,43,1,44,1,44,1,44,1,44,3,44,517,8,44,1,45, + 1,45,1,45,1,45,1,46,1,46,1,46,1,47,1,47,1,47,5,47,529,8,47,10,47,12,47, + 532,9,47,1,48,1,48,1,48,1,48,1,49,1,49,1,50,1,50,3,50,542,8,50,1,51,3,51, + 545,8,51,1,51,1,51,1,52,3,52,550,8,52,1,52,1,52,1,53,1,53,1,54,1,54,1,55, + 1,55,1,55,1,56,1,56,1,56,1,56,1,57,1,57,1,57,1,58,1,58,1,58,1,58,3,58,572, + 8,58,1,58,1,58,1,58,1,58,5,58,578,8,58,10,58,12,58,581,9,58,3,58,583,8, + 58,1,59,1,59,1,59,3,59,588,8,59,1,59,1,59,1,60,1,60,1,60,1,60,1,60,1,61, + 1,61,1,61,1,61,3,61,601,8,61,1,61,0,4,2,10,18,20,62,0,2,4,6,8,10,12,14, + 16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62, + 64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108, + 110,112,114,116,118,120,122,0,8,1,0,59,60,1,0,61,63,2,0,26,26,76,76,1,0, + 67,68,2,0,31,31,35,35,2,0,38,38,41,41,2,0,37,37,51,51,2,0,52,52,54,58,628, + 0,124,1,0,0,0,2,127,1,0,0,0,4,144,1,0,0,0,6,162,1,0,0,0,8,164,1,0,0,0,10, + 197,1,0,0,0,12,224,1,0,0,0,14,226,1,0,0,0,16,235,1,0,0,0,18,241,1,0,0,0, + 20,262,1,0,0,0,22,272,1,0,0,0,24,287,1,0,0,0,26,289,1,0,0,0,28,291,1,0, + 0,0,30,294,1,0,0,0,32,305,1,0,0,0,34,309,1,0,0,0,36,324,1,0,0,0,38,328, + 1,0,0,0,40,330,1,0,0,0,42,334,1,0,0,0,44,336,1,0,0,0,46,345,1,0,0,0,48, + 349,1,0,0,0,50,365,1,0,0,0,52,368,1,0,0,0,54,376,1,0,0,0,56,384,1,0,0,0, + 58,389,1,0,0,0,60,397,1,0,0,0,62,405,1,0,0,0,64,413,1,0,0,0,66,418,1,0, + 0,0,68,462,1,0,0,0,70,466,1,0,0,0,72,471,1,0,0,0,74,473,1,0,0,0,76,476, + 1,0,0,0,78,485,1,0,0,0,80,493,1,0,0,0,82,496,1,0,0,0,84,499,1,0,0,0,86, + 508,1,0,0,0,88,512,1,0,0,0,90,518,1,0,0,0,92,522,1,0,0,0,94,525,1,0,0,0, + 96,533,1,0,0,0,98,537,1,0,0,0,100,541,1,0,0,0,102,544,1,0,0,0,104,549,1, + 0,0,0,106,553,1,0,0,0,108,555,1,0,0,0,110,557,1,0,0,0,112,560,1,0,0,0,114, + 564,1,0,0,0,116,567,1,0,0,0,118,587,1,0,0,0,120,591,1,0,0,0,122,596,1,0, + 0,0,124,125,3,2,1,0,125,126,5,0,0,1,126,1,1,0,0,0,127,128,6,1,-1,0,128, + 129,3,4,2,0,129,135,1,0,0,0,130,131,10,1,0,0,131,132,5,25,0,0,132,134,3, + 6,3,0,133,130,1,0,0,0,134,137,1,0,0,0,135,133,1,0,0,0,135,136,1,0,0,0,136, + 3,1,0,0,0,137,135,1,0,0,0,138,145,3,110,55,0,139,145,3,34,17,0,140,145, + 3,28,14,0,141,145,3,114,57,0,142,143,4,2,1,0,143,145,3,48,24,0,144,138, + 1,0,0,0,144,139,1,0,0,0,144,140,1,0,0,0,144,141,1,0,0,0,144,142,1,0,0,0, + 145,5,1,0,0,0,146,163,3,50,25,0,147,163,3,8,4,0,148,163,3,80,40,0,149,163, + 3,74,37,0,150,163,3,52,26,0,151,163,3,76,38,0,152,163,3,82,41,0,153,163, + 3,84,42,0,154,163,3,88,44,0,155,163,3,90,45,0,156,163,3,116,58,0,157,163, + 3,92,46,0,158,159,4,3,2,0,159,163,3,122,61,0,160,161,4,3,3,0,161,163,3, + 120,60,0,162,146,1,0,0,0,162,147,1,0,0,0,162,148,1,0,0,0,162,149,1,0,0, + 0,162,150,1,0,0,0,162,151,1,0,0,0,162,152,1,0,0,0,162,153,1,0,0,0,162,154, + 1,0,0,0,162,155,1,0,0,0,162,156,1,0,0,0,162,157,1,0,0,0,162,158,1,0,0,0, + 162,160,1,0,0,0,163,7,1,0,0,0,164,165,5,16,0,0,165,166,3,10,5,0,166,9,1, + 0,0,0,167,168,6,5,-1,0,168,169,5,44,0,0,169,198,3,10,5,8,170,198,3,16,8, + 0,171,198,3,12,6,0,172,174,3,16,8,0,173,175,5,44,0,0,174,173,1,0,0,0,174, + 175,1,0,0,0,175,176,1,0,0,0,176,177,5,39,0,0,177,178,5,43,0,0,178,183,3, + 16,8,0,179,180,5,34,0,0,180,182,3,16,8,0,181,179,1,0,0,0,182,185,1,0,0, + 0,183,181,1,0,0,0,183,184,1,0,0,0,184,186,1,0,0,0,185,183,1,0,0,0,186,187, + 5,50,0,0,187,198,1,0,0,0,188,189,3,16,8,0,189,191,5,40,0,0,190,192,5,44, + 0,0,191,190,1,0,0,0,191,192,1,0,0,0,192,193,1,0,0,0,193,194,5,45,0,0,194, + 198,1,0,0,0,195,196,4,5,4,0,196,198,3,14,7,0,197,167,1,0,0,0,197,170,1, + 0,0,0,197,171,1,0,0,0,197,172,1,0,0,0,197,188,1,0,0,0,197,195,1,0,0,0,198, + 207,1,0,0,0,199,200,10,5,0,0,200,201,5,30,0,0,201,206,3,10,5,6,202,203, + 10,4,0,0,203,204,5,47,0,0,204,206,3,10,5,5,205,199,1,0,0,0,205,202,1,0, + 0,0,206,209,1,0,0,0,207,205,1,0,0,0,207,208,1,0,0,0,208,11,1,0,0,0,209, + 207,1,0,0,0,210,212,3,16,8,0,211,213,5,44,0,0,212,211,1,0,0,0,212,213,1, + 0,0,0,213,214,1,0,0,0,214,215,5,42,0,0,215,216,3,106,53,0,216,225,1,0,0, + 0,217,219,3,16,8,0,218,220,5,44,0,0,219,218,1,0,0,0,219,220,1,0,0,0,220, + 221,1,0,0,0,221,222,5,49,0,0,222,223,3,106,53,0,223,225,1,0,0,0,224,210, + 1,0,0,0,224,217,1,0,0,0,225,13,1,0,0,0,226,227,3,58,29,0,227,228,5,24,0, + 0,228,229,3,68,34,0,229,15,1,0,0,0,230,236,3,18,9,0,231,232,3,18,9,0,232, + 233,3,108,54,0,233,234,3,18,9,0,234,236,1,0,0,0,235,230,1,0,0,0,235,231, + 1,0,0,0,236,17,1,0,0,0,237,238,6,9,-1,0,238,242,3,20,10,0,239,240,7,0,0, + 0,240,242,3,18,9,3,241,237,1,0,0,0,241,239,1,0,0,0,242,251,1,0,0,0,243, + 244,10,2,0,0,244,245,7,1,0,0,245,250,3,18,9,3,246,247,10,1,0,0,247,248, + 7,0,0,0,248,250,3,18,9,2,249,243,1,0,0,0,249,246,1,0,0,0,250,253,1,0,0, + 0,251,249,1,0,0,0,251,252,1,0,0,0,252,19,1,0,0,0,253,251,1,0,0,0,254,255, + 6,10,-1,0,255,263,3,68,34,0,256,263,3,58,29,0,257,263,3,22,11,0,258,259, + 5,43,0,0,259,260,3,10,5,0,260,261,5,50,0,0,261,263,1,0,0,0,262,254,1,0, + 0,0,262,256,1,0,0,0,262,257,1,0,0,0,262,258,1,0,0,0,263,269,1,0,0,0,264, + 265,10,1,0,0,265,266,5,33,0,0,266,268,3,26,13,0,267,264,1,0,0,0,268,271, + 1,0,0,0,269,267,1,0,0,0,269,270,1,0,0,0,270,21,1,0,0,0,271,269,1,0,0,0, + 272,273,3,24,12,0,273,283,5,43,0,0,274,284,5,61,0,0,275,280,3,10,5,0,276, + 277,5,34,0,0,277,279,3,10,5,0,278,276,1,0,0,0,279,282,1,0,0,0,280,278,1, + 0,0,0,280,281,1,0,0,0,281,284,1,0,0,0,282,280,1,0,0,0,283,274,1,0,0,0,283, + 275,1,0,0,0,283,284,1,0,0,0,284,285,1,0,0,0,285,286,5,50,0,0,286,23,1,0, + 0,0,287,288,3,72,36,0,288,25,1,0,0,0,289,290,3,64,32,0,290,27,1,0,0,0,291, + 292,5,12,0,0,292,293,3,30,15,0,293,29,1,0,0,0,294,299,3,32,16,0,295,296, + 5,34,0,0,296,298,3,32,16,0,297,295,1,0,0,0,298,301,1,0,0,0,299,297,1,0, + 0,0,299,300,1,0,0,0,300,31,1,0,0,0,301,299,1,0,0,0,302,303,3,58,29,0,303, + 304,5,32,0,0,304,306,1,0,0,0,305,302,1,0,0,0,305,306,1,0,0,0,306,307,1, + 0,0,0,307,308,3,10,5,0,308,33,1,0,0,0,309,310,5,6,0,0,310,315,3,36,18,0, + 311,312,5,34,0,0,312,314,3,36,18,0,313,311,1,0,0,0,314,317,1,0,0,0,315, + 313,1,0,0,0,315,316,1,0,0,0,316,319,1,0,0,0,317,315,1,0,0,0,318,320,3,42, + 21,0,319,318,1,0,0,0,319,320,1,0,0,0,320,35,1,0,0,0,321,322,3,38,19,0,322, + 323,5,24,0,0,323,325,1,0,0,0,324,321,1,0,0,0,324,325,1,0,0,0,325,326,1, + 0,0,0,326,327,3,40,20,0,327,37,1,0,0,0,328,329,5,76,0,0,329,39,1,0,0,0, + 330,331,7,2,0,0,331,41,1,0,0,0,332,335,3,44,22,0,333,335,3,46,23,0,334, + 332,1,0,0,0,334,333,1,0,0,0,335,43,1,0,0,0,336,337,5,75,0,0,337,342,5,76, + 0,0,338,339,5,34,0,0,339,341,5,76,0,0,340,338,1,0,0,0,341,344,1,0,0,0,342, + 340,1,0,0,0,342,343,1,0,0,0,343,45,1,0,0,0,344,342,1,0,0,0,345,346,5,65, + 0,0,346,347,3,44,22,0,347,348,5,66,0,0,348,47,1,0,0,0,349,350,5,19,0,0, + 350,355,3,36,18,0,351,352,5,34,0,0,352,354,3,36,18,0,353,351,1,0,0,0,354, + 357,1,0,0,0,355,353,1,0,0,0,355,356,1,0,0,0,356,359,1,0,0,0,357,355,1,0, + 0,0,358,360,3,54,27,0,359,358,1,0,0,0,359,360,1,0,0,0,360,363,1,0,0,0,361, + 362,5,29,0,0,362,364,3,30,15,0,363,361,1,0,0,0,363,364,1,0,0,0,364,49,1, + 0,0,0,365,366,5,4,0,0,366,367,3,30,15,0,367,51,1,0,0,0,368,370,5,15,0,0, + 369,371,3,54,27,0,370,369,1,0,0,0,370,371,1,0,0,0,371,374,1,0,0,0,372,373, + 5,29,0,0,373,375,3,30,15,0,374,372,1,0,0,0,374,375,1,0,0,0,375,53,1,0,0, + 0,376,381,3,56,28,0,377,378,5,34,0,0,378,380,3,56,28,0,379,377,1,0,0,0, + 380,383,1,0,0,0,381,379,1,0,0,0,381,382,1,0,0,0,382,55,1,0,0,0,383,381, + 1,0,0,0,384,387,3,32,16,0,385,386,5,16,0,0,386,388,3,10,5,0,387,385,1,0, + 0,0,387,388,1,0,0,0,388,57,1,0,0,0,389,394,3,72,36,0,390,391,5,36,0,0,391, + 393,3,72,36,0,392,390,1,0,0,0,393,396,1,0,0,0,394,392,1,0,0,0,394,395,1, + 0,0,0,395,59,1,0,0,0,396,394,1,0,0,0,397,402,3,66,33,0,398,399,5,36,0,0, + 399,401,3,66,33,0,400,398,1,0,0,0,401,404,1,0,0,0,402,400,1,0,0,0,402,403, + 1,0,0,0,403,61,1,0,0,0,404,402,1,0,0,0,405,410,3,60,30,0,406,407,5,34,0, + 0,407,409,3,60,30,0,408,406,1,0,0,0,409,412,1,0,0,0,410,408,1,0,0,0,410, + 411,1,0,0,0,411,63,1,0,0,0,412,410,1,0,0,0,413,414,7,3,0,0,414,65,1,0,0, + 0,415,419,5,80,0,0,416,417,4,33,10,0,417,419,3,70,35,0,418,415,1,0,0,0, + 418,416,1,0,0,0,419,67,1,0,0,0,420,463,5,45,0,0,421,422,3,104,52,0,422, + 423,5,67,0,0,423,463,1,0,0,0,424,463,3,102,51,0,425,463,3,104,52,0,426, + 463,3,98,49,0,427,463,3,70,35,0,428,463,3,106,53,0,429,430,5,65,0,0,430, + 435,3,100,50,0,431,432,5,34,0,0,432,434,3,100,50,0,433,431,1,0,0,0,434, + 437,1,0,0,0,435,433,1,0,0,0,435,436,1,0,0,0,436,438,1,0,0,0,437,435,1,0, + 0,0,438,439,5,66,0,0,439,463,1,0,0,0,440,441,5,65,0,0,441,446,3,98,49,0, + 442,443,5,34,0,0,443,445,3,98,49,0,444,442,1,0,0,0,445,448,1,0,0,0,446, + 444,1,0,0,0,446,447,1,0,0,0,447,449,1,0,0,0,448,446,1,0,0,0,449,450,5,66, + 0,0,450,463,1,0,0,0,451,452,5,65,0,0,452,457,3,106,53,0,453,454,5,34,0, + 0,454,456,3,106,53,0,455,453,1,0,0,0,456,459,1,0,0,0,457,455,1,0,0,0,457, + 458,1,0,0,0,458,460,1,0,0,0,459,457,1,0,0,0,460,461,5,66,0,0,461,463,1, + 0,0,0,462,420,1,0,0,0,462,421,1,0,0,0,462,424,1,0,0,0,462,425,1,0,0,0,462, + 426,1,0,0,0,462,427,1,0,0,0,462,428,1,0,0,0,462,429,1,0,0,0,462,440,1,0, + 0,0,462,451,1,0,0,0,463,69,1,0,0,0,464,467,5,48,0,0,465,467,5,64,0,0,466, + 464,1,0,0,0,466,465,1,0,0,0,467,71,1,0,0,0,468,472,3,64,32,0,469,470,4, + 36,11,0,470,472,3,70,35,0,471,468,1,0,0,0,471,469,1,0,0,0,472,73,1,0,0, + 0,473,474,5,9,0,0,474,475,5,27,0,0,475,75,1,0,0,0,476,477,5,14,0,0,477, + 482,3,78,39,0,478,479,5,34,0,0,479,481,3,78,39,0,480,478,1,0,0,0,481,484, + 1,0,0,0,482,480,1,0,0,0,482,483,1,0,0,0,483,77,1,0,0,0,484,482,1,0,0,0, + 485,487,3,10,5,0,486,488,7,4,0,0,487,486,1,0,0,0,487,488,1,0,0,0,488,491, + 1,0,0,0,489,490,5,46,0,0,490,492,7,5,0,0,491,489,1,0,0,0,491,492,1,0,0, + 0,492,79,1,0,0,0,493,494,5,8,0,0,494,495,3,62,31,0,495,81,1,0,0,0,496,497, + 5,2,0,0,497,498,3,62,31,0,498,83,1,0,0,0,499,500,5,11,0,0,500,505,3,86, + 43,0,501,502,5,34,0,0,502,504,3,86,43,0,503,501,1,0,0,0,504,507,1,0,0,0, + 505,503,1,0,0,0,505,506,1,0,0,0,506,85,1,0,0,0,507,505,1,0,0,0,508,509, + 3,60,30,0,509,510,5,84,0,0,510,511,3,60,30,0,511,87,1,0,0,0,512,513,5,1, + 0,0,513,514,3,20,10,0,514,516,3,106,53,0,515,517,3,94,47,0,516,515,1,0, + 0,0,516,517,1,0,0,0,517,89,1,0,0,0,518,519,5,7,0,0,519,520,3,20,10,0,520, + 521,3,106,53,0,521,91,1,0,0,0,522,523,5,10,0,0,523,524,3,58,29,0,524,93, + 1,0,0,0,525,530,3,96,48,0,526,527,5,34,0,0,527,529,3,96,48,0,528,526,1, + 0,0,0,529,532,1,0,0,0,530,528,1,0,0,0,530,531,1,0,0,0,531,95,1,0,0,0,532, + 530,1,0,0,0,533,534,3,64,32,0,534,535,5,32,0,0,535,536,3,68,34,0,536,97, + 1,0,0,0,537,538,7,6,0,0,538,99,1,0,0,0,539,542,3,102,51,0,540,542,3,104, + 52,0,541,539,1,0,0,0,541,540,1,0,0,0,542,101,1,0,0,0,543,545,7,0,0,0,544, + 543,1,0,0,0,544,545,1,0,0,0,545,546,1,0,0,0,546,547,5,28,0,0,547,103,1, + 0,0,0,548,550,7,0,0,0,549,548,1,0,0,0,549,550,1,0,0,0,550,551,1,0,0,0,551, + 552,5,27,0,0,552,105,1,0,0,0,553,554,5,26,0,0,554,107,1,0,0,0,555,556,7, + 7,0,0,556,109,1,0,0,0,557,558,5,5,0,0,558,559,3,112,56,0,559,111,1,0,0, + 0,560,561,5,65,0,0,561,562,3,2,1,0,562,563,5,66,0,0,563,113,1,0,0,0,564, + 565,5,13,0,0,565,566,5,100,0,0,566,115,1,0,0,0,567,568,5,3,0,0,568,571, + 5,90,0,0,569,570,5,88,0,0,570,572,3,60,30,0,571,569,1,0,0,0,571,572,1,0, + 0,0,572,582,1,0,0,0,573,574,5,89,0,0,574,579,3,118,59,0,575,576,5,34,0, + 0,576,578,3,118,59,0,577,575,1,0,0,0,578,581,1,0,0,0,579,577,1,0,0,0,579, + 580,1,0,0,0,580,583,1,0,0,0,581,579,1,0,0,0,582,573,1,0,0,0,582,583,1,0, + 0,0,583,117,1,0,0,0,584,585,3,60,30,0,585,586,5,32,0,0,586,588,1,0,0,0, + 587,584,1,0,0,0,587,588,1,0,0,0,588,589,1,0,0,0,589,590,3,60,30,0,590,119, + 1,0,0,0,591,592,5,18,0,0,592,593,3,36,18,0,593,594,5,88,0,0,594,595,3,62, + 31,0,595,121,1,0,0,0,596,597,5,17,0,0,597,600,3,54,27,0,598,599,5,29,0, + 0,599,601,3,30,15,0,600,598,1,0,0,0,600,601,1,0,0,0,601,123,1,0,0,0,58, 135,144,162,174,183,191,197,205,207,212,219,224,235,241,249,251,262,269, - 280,283,289,301,307,317,321,326,336,344,357,361,365,372,376,383,389,396, - 404,412,420,437,448,459,464,468,473,484,489,493,507,518,532,543,546,551, - 573,581,584,589,602]; + 280,283,299,305,315,319,324,334,342,355,359,363,370,374,381,387,394,402, + 410,418,435,446,457,462,466,471,482,487,491,505,516,530,541,544,549,571, + 579,582,587,600]; private static __ATN: ATN; public static get _ATN(): ATN { @@ -4124,19 +4107,20 @@ export class RegexBooleanExpressionContext extends ParserRuleContext { export class MatchBooleanExpressionContext extends ParserRuleContext { - public _queryString!: StringContext; + public _fieldExp!: QualifiedNameContext; + public _queryString!: ConstantContext; constructor(parser?: esql_parser, parent?: ParserRuleContext, invokingState?: number) { super(parent, invokingState); this.parser = parser; } - public valueExpression(): ValueExpressionContext { - return this.getTypedRuleContext(ValueExpressionContext, 0) as ValueExpressionContext; + public COLON(): TerminalNode { + return this.getToken(esql_parser.COLON, 0); } - public MATCH(): TerminalNode { - return this.getToken(esql_parser.MATCH, 0); + public qualifiedName(): QualifiedNameContext { + return this.getTypedRuleContext(QualifiedNameContext, 0) as QualifiedNameContext; } - public string_(): StringContext { - return this.getTypedRuleContext(StringContext, 0) as StringContext; + public constant(): ConstantContext { + return this.getTypedRuleContext(ConstantContext, 0) as ConstantContext; } public get ruleIndex(): number { return esql_parser.RULE_matchBooleanExpression; @@ -4484,9 +4468,6 @@ export class FunctionNameContext extends ParserRuleContext { super(parent, invokingState); this.parser = parser; } - public MATCH(): TerminalNode { - return this.getToken(esql_parser.MATCH, 0); - } public identifierOrParameter(): IdentifierOrParameterContext { return this.getTypedRuleContext(IdentifierOrParameterContext, 0) as IdentifierOrParameterContext; } diff --git a/packages/kbn-esql-ast/src/builder/builder.ts b/packages/kbn-esql-ast/src/builder/builder.ts index 894ab99e5b3e..fae1981b454c 100644 --- a/packages/kbn-esql-ast/src/builder/builder.ts +++ b/packages/kbn-esql-ast/src/builder/builder.ts @@ -9,6 +9,7 @@ /* eslint-disable @typescript-eslint/no-namespace */ +import { LeafPrinter } from '../pretty_print'; import { ESQLAstComment, ESQLAstCommentMultiLine, @@ -125,16 +126,23 @@ export namespace Builder { }; export const column = ( - template: Omit, 'name' | 'quoted'>, + template: Omit, 'name' | 'quoted' | 'parts'>, fromParser?: Partial ): ESQLColumn => { - return { + const node: ESQLColumn = { ...template, ...Builder.parserFields(fromParser), + parts: template.args.map((arg) => + arg.type === 'identifier' ? arg.name : LeafPrinter.param(arg) + ), quoted: false, - name: template.parts.join('.'), + name: '', type: 'column', }; + + node.name = LeafPrinter.column(node); + + return node; }; export const order = ( diff --git a/packages/kbn-esql-ast/src/mutate/commands/from/metadata.test.ts b/packages/kbn-esql-ast/src/mutate/commands/from/metadata.test.ts index b6cb485395a6..e4161994d224 100644 --- a/packages/kbn-esql-ast/src/mutate/commands/from/metadata.test.ts +++ b/packages/kbn-esql-ast/src/mutate/commands/from/metadata.test.ts @@ -28,7 +28,13 @@ describe('commands.from.metadata', () => { expect(column).toMatchObject({ type: 'column', - parts: ['a'], + args: [ + { + type: 'identifier', + name: 'a', + }, + ], + // parts: ['a'], }); }); @@ -40,19 +46,39 @@ describe('commands.from.metadata', () => { expect(columns).toMatchObject([ { type: 'column', - parts: ['a'], + args: [ + { + type: 'identifier', + name: 'a', + }, + ], }, { type: 'column', - parts: ['b'], + args: [ + { + type: 'identifier', + name: 'b', + }, + ], }, { type: 'column', - parts: ['_id'], + args: [ + { + type: 'identifier', + name: '_id', + }, + ], }, { type: 'column', - parts: ['_lang'], + args: [ + { + type: 'identifier', + name: '_lang', + }, + ], }, ]); }); @@ -156,7 +182,6 @@ describe('commands.from.metadata', () => { it('return inserted `column` node, and parent `option` node', () => { const src1 = 'FROM index METADATA a'; const { root } = parse(src1); - const tuple = commands.from.metadata.insert(root, 'b'); expect(tuple).toMatchObject([ diff --git a/packages/kbn-esql-ast/src/mutate/commands/from/metadata.ts b/packages/kbn-esql-ast/src/mutate/commands/from/metadata.ts index 5160ab65954c..4d637a1fd057 100644 --- a/packages/kbn-esql-ast/src/mutate/commands/from/metadata.ts +++ b/packages/kbn-esql-ast/src/mutate/commands/from/metadata.ts @@ -74,7 +74,10 @@ export const find = ( } const predicate: Predicate<[ESQLColumn, unknown]> = ([field]) => - cmpArr(field.parts, fieldName as string[]); + cmpArr( + field.args.map((arg) => (arg.type === 'identifier' ? arg.name : '')), + fieldName as string[] + ); return findByPredicate(list(ast), predicate); }; @@ -128,7 +131,12 @@ export const remove = ( fieldName = [fieldName]; } - return removeByPredicate(ast, (field) => cmpArr(field.parts, fieldName as string[])); + return removeByPredicate(ast, (field) => + cmpArr( + field.args.map((arg) => (arg.type === 'identifier' ? arg.name : '')), + fieldName as string[] + ) + ); }; /** @@ -161,7 +169,8 @@ export const insert = ( } const parts: string[] = typeof fieldName === 'string' ? [fieldName] : fieldName; - const column = Builder.expression.column({ parts }); + const args = parts.map((part) => Builder.identifier({ name: part })); + const column = Builder.expression.column({ args }); if (index === -1) { option.args.push(column); @@ -195,7 +204,12 @@ export const upsert = ( const parts = Array.isArray(fieldName) ? fieldName : [fieldName]; const existing = Walker.find( option, - (node) => node.type === 'column' && cmpArr(node.parts, parts) + (node) => + node.type === 'column' && + cmpArr( + node.args.map((arg) => (arg.type === 'identifier' ? arg.name : '')), + parts + ) ); if (existing) { return undefined; diff --git a/packages/kbn-esql-ast/src/mutate/commands/index.ts b/packages/kbn-esql-ast/src/mutate/commands/index.ts index 9e2599c49345..8068aa5d3ef9 100644 --- a/packages/kbn-esql-ast/src/mutate/commands/index.ts +++ b/packages/kbn-esql-ast/src/mutate/commands/index.ts @@ -10,5 +10,6 @@ import * as from from './from'; import * as limit from './limit'; import * as sort from './sort'; +import * as stats from './stats'; -export { from, limit, sort }; +export { from, limit, sort, stats }; diff --git a/packages/kbn-esql-ast/src/mutate/commands/sort/index.test.ts b/packages/kbn-esql-ast/src/mutate/commands/sort/index.test.ts index d04f79b96541..1342a059254f 100644 --- a/packages/kbn-esql-ast/src/mutate/commands/sort/index.test.ts +++ b/packages/kbn-esql-ast/src/mutate/commands/sort/index.test.ts @@ -244,13 +244,13 @@ describe('commands.sort', () => { args: [ { type: 'column', - parts: ['b', 'a'], + args: [{ name: 'b' }, { name: 'a' }], }, ], }); expect(node2).toMatchObject({ type: 'column', - parts: ['a', 'b'], + args: [{ name: 'a' }, { name: 'b' }], }); }); diff --git a/packages/kbn-esql-ast/src/mutate/commands/sort/index.ts b/packages/kbn-esql-ast/src/mutate/commands/sort/index.ts index d2b2c7cd5f3d..d2f64e5b6a1c 100644 --- a/packages/kbn-esql-ast/src/mutate/commands/sort/index.ts +++ b/packages/kbn-esql-ast/src/mutate/commands/sort/index.ts @@ -49,15 +49,17 @@ export type NewSortExpressionTemplate = const createSortExpression = ( template: string | string[] | NewSortExpressionTemplate ): SortExpression => { + const parts: string[] = + typeof template === 'string' + ? [template] + : Array.isArray(template) + ? template + : typeof template.parts === 'string' + ? [template.parts] + : template.parts; + const identifiers = parts.map((part) => Builder.identifier({ name: part })); const column = Builder.expression.column({ - parts: - typeof template === 'string' - ? [template] - : Array.isArray(template) - ? template - : typeof template.parts === 'string' - ? [template.parts] - : template.parts, + args: identifiers, }); if (typeof template === 'string' || Array.isArray(template)) { @@ -189,12 +191,18 @@ export const find = ( return findByPredicate(ast, ([node]) => { let isMatch = false; if (node.type === 'column') { - isMatch = util.cmpArr(node.parts, arrParts); + isMatch = util.cmpArr( + node.args.map((arg) => (arg.type === 'identifier' ? arg.name : '')), + arrParts + ); } else if (node.type === 'order') { - const columnParts = (node.args[0] as ESQLColumn)?.parts; + const columnParts = (node.args[0] as ESQLColumn)?.args; if (Array.isArray(columnParts)) { - isMatch = util.cmpArr(columnParts, arrParts); + isMatch = util.cmpArr( + columnParts.map((arg) => (arg.type === 'identifier' ? arg.name : '')), + arrParts + ); } } diff --git a/packages/kbn-esql-ast/src/mutate/commands/stats/index.test.ts b/packages/kbn-esql-ast/src/mutate/commands/stats/index.test.ts new file mode 100644 index 000000000000..6fdafa45e383 --- /dev/null +++ b/packages/kbn-esql-ast/src/mutate/commands/stats/index.test.ts @@ -0,0 +1,317 @@ +/* + * Copyright 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 * as commands from '..'; +import { EsqlQuery } from '../../../query'; + +describe('commands.stats', () => { + describe('.list()', () => { + it('lists all "STATS" commands', () => { + const src = 'FROM index | LIMIT 1 | STATS agg() | LIMIT 2 | STATS max()'; + const query = EsqlQuery.fromSrc(src); + + const nodes = [...commands.stats.list(query.ast)]; + + expect(nodes).toMatchObject([ + { + type: 'command', + name: 'stats', + args: [ + { + type: 'function', + name: 'agg', + }, + ], + }, + { + type: 'command', + name: 'stats', + args: [ + { + type: 'function', + name: 'max', + }, + ], + }, + ]); + }); + }); + + describe('.byIndex()', () => { + it('retrieves the specific "STATS" command by index', () => { + const src = 'FROM index | LIMIT 1 | STATS agg() | LIMIT 2 | STATS max()'; + const query = EsqlQuery.fromSrc(src); + + const node1 = commands.stats.byIndex(query.ast, 1); + const node2 = commands.stats.byIndex(query.ast, 0); + + expect(node1).toMatchObject({ + type: 'command', + name: 'stats', + args: [ + { + type: 'function', + name: 'max', + }, + ], + }); + expect(node2).toMatchObject({ + type: 'command', + name: 'stats', + args: [ + { + type: 'function', + name: 'agg', + }, + ], + }); + }); + }); + + describe('.summarizeCommand()', () => { + it('returns summary of a simple field, defined through assignment', () => { + const src = 'FROM index | STATS foo = agg(bar)'; + const query = EsqlQuery.fromSrc(src); + + const command = commands.stats.byIndex(query.ast, 0)!; + const summary = commands.stats.summarizeCommand(query, command); + + expect(summary).toMatchObject({ + command, + aggregates: { + foo: { + arg: { + type: 'function', + name: '=', + }, + field: 'foo', + column: { + type: 'column', + name: 'foo', + }, + definition: { + type: 'function', + name: 'agg', + args: [ + { + type: 'column', + name: 'bar', + }, + ], + }, + terminals: [ + { + type: 'column', + name: 'bar', + }, + ], + fields: ['bar'], + }, + }, + }); + }); + + it('can summarize field defined without assignment', () => { + const src = 'FROM index | STATS agg( /* haha 😅 */ max(foo), bar, baz)'; + const query = EsqlQuery.fromSrc(src); + + const command = commands.stats.byIndex(query.ast, 0)!; + const summary = commands.stats.summarizeCommand(query, command); + + expect(summary).toMatchObject({ + command, + aggregates: { + '`agg( /* haha 😅 */ max(foo), bar, baz)`': { + arg: { + type: 'function', + name: 'agg', + }, + field: '`agg( /* haha 😅 */ max(foo), bar, baz)`', + column: { + type: 'column', + name: '`agg( /* haha 😅 */ max(foo), bar, baz)`', + }, + definition: { + type: 'function', + name: 'agg', + }, + terminals: [ + { + type: 'column', + name: 'foo', + }, + { + type: 'column', + name: 'bar', + }, + { + type: 'column', + name: 'baz', + }, + ], + fields: ['foo', 'bar', 'baz'], + }, + }, + }); + }); + + it('returns a map of stats about two fields', () => { + const src = 'FROM index | STATS foo = agg(f1) + agg(f2), a.b = agg(f3)'; + const query = EsqlQuery.fromSrc(src); + + const command = commands.stats.byIndex(query.ast, 0)!; + const summary = commands.stats.summarizeCommand(query, command); + + expect(summary).toMatchObject({ + aggregates: { + foo: { + field: 'foo', + fields: ['f1', 'f2'], + }, + 'a.b': { + field: 'a.b', + fields: ['f3'], + }, + }, + }); + expect(summary.fields).toEqual(new Set(['f1', 'f2', 'f3'])); + }); + + it('can get de-duplicated list of used fields', () => { + const src = 'FROM index | STATS foo = agg(f1) + agg(f2), a.b = agg(f1)'; + const query = EsqlQuery.fromSrc(src); + + const command = commands.stats.byIndex(query.ast, 0)!; + const summary = commands.stats.summarizeCommand(query, command); + + expect(summary.fields).toEqual(new Set(['f1', 'f2'])); + }); + + describe('params', () => { + it('can use params as source field names', () => { + const src = 'FROM index | STATS foo = agg(f1.?aha) + ?aha(?nested.?param), a.b = agg(f1)'; + const query = EsqlQuery.fromSrc(src); + + const command = commands.stats.byIndex(query.ast, 0)!; + const summary = commands.stats.summarizeCommand(query, command); + + expect(summary).toMatchObject({ + aggregates: { + foo: { + fields: ['f1.?aha', '?nested.?param'], + }, + 'a.b': { + fields: ['f1'], + }, + }, + }); + expect(summary.fields).toEqual(new Set(['f1.?aha', '?nested.?param', 'f1'])); + }); + + it('can use params as destination field names', () => { + const src = 'FROM index | STATS ?dest = agg(asdf) BY asdf'; + const query = EsqlQuery.fromSrc(src); + + const command = commands.stats.byIndex(query.ast, 0)!; + const summary = commands.stats.summarizeCommand(query, command); + + expect(summary).toMatchObject({ + aggregates: { + '?dest': { + fields: ['asdf'], + }, + }, + }); + expect(summary.fields).toEqual(new Set(['asdf'])); + }); + }); + + describe('BY option', () => { + it('can collect fields from the BY option', () => { + const src = 'FROM index | STATS max(1) BY abc'; + const query = EsqlQuery.fromSrc(src); + + const command = commands.stats.byIndex(query.ast, 0)!; + const summary = commands.stats.summarizeCommand(query, command); + + expect(summary.aggregates).toEqual({ + '`max(1)`': expect.any(Object), + }); + expect(summary.fields).toEqual(new Set(['abc'])); + }); + + it('returns all "grouping" fields', () => { + const src = 'FROM index | STATS max(1) BY a, b, c'; + const query = EsqlQuery.fromSrc(src); + + const command = commands.stats.byIndex(query.ast, 0)!; + const summary = commands.stats.summarizeCommand(query, command); + + expect(summary.aggregates).toEqual({ + '`max(1)`': expect.any(Object), + }); + expect(summary.grouping).toMatchObject({ + a: { type: 'column' }, + b: { type: 'column' }, + c: { type: 'column' }, + }); + }); + + it('can have params and quoted fields in grouping', () => { + const src = 'FROM index | STATS max(1) BY `a😎`, ?123, a.?b.?0.`😎`'; + const query = EsqlQuery.fromSrc(src); + + const command = commands.stats.byIndex(query.ast, 0)!; + const summary = commands.stats.summarizeCommand(query, command); + + expect(summary.aggregates).toEqual({ + '`max(1)`': expect.any(Object), + }); + expect(summary.grouping).toMatchObject({ + '`a😎`': { type: 'column' }, + // '?123': { type: 'column' }, + 'a.?b.?0.`😎`': { type: 'column' }, + }); + }); + }); + }); + + describe('.summarize()', () => { + it('can summarize multiple stats commands', () => { + const src = 'FROM index | LIMIT 1 | STATS agg() | LIMIT 2 | STATS max(a, b, c), max2(d.e)'; + const query = EsqlQuery.fromSrc(src); + const summary = commands.stats.summarize(query); + + expect(summary).toMatchObject([ + { + aggregates: { + '`agg()`': { + field: '`agg()`', + fields: [], + }, + }, + fields: new Set([]), + }, + { + aggregates: { + '`max(a, b, c)`': { + field: '`max(a, b, c)`', + fields: ['a', 'b', 'c'], + }, + '`max2(d.e)`': { + field: '`max2(d.e)`', + fields: ['d.e'], + }, + }, + fields: new Set(['a', 'b', 'c', 'd.e']), + }, + ]); + }); + }); +}); diff --git a/packages/kbn-esql-ast/src/mutate/commands/stats/index.ts b/packages/kbn-esql-ast/src/mutate/commands/stats/index.ts new file mode 100644 index 000000000000..9a07549c0e0e --- /dev/null +++ b/packages/kbn-esql-ast/src/mutate/commands/stats/index.ts @@ -0,0 +1,234 @@ +/* + * Copyright 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 { Walker } from '../../../walker'; +import { Visitor } from '../../../visitor'; +import { LeafPrinter } from '../../../pretty_print'; +import { Builder } from '../../../builder'; +import { singleItems } from '../../../visitor/utils'; +import type { + ESQLAstQueryExpression, + ESQLColumn, + ESQLCommand, + ESQLList, + ESQLLiteral, + ESQLProperNode, + ESQLTimeInterval, +} from '../../../types'; +import * as generic from '../../generic'; +import { isColumn, isFunctionExpression } from '../../../ast/helpers'; +import type { EsqlQuery } from '../../../query'; + +/** + * Lists all "LIMIT" commands in the query AST. + * + * @param ast The root AST node to search for "LIMIT" commands. + * @returns A collection of "LIMIT" commands. + */ +export const list = (ast: ESQLAstQueryExpression): IterableIterator => { + return generic.commands.list(ast, (cmd) => cmd.name === 'stats'); +}; + +/** + * Retrieves the "LIMIT" command at the specified index in order of appearance. + * + * @param ast The root AST node to search for "LIMIT" commands. + * @param index The index of the "LIMIT" command to retrieve. + * @returns The "LIMIT" command at the specified index, if any. + */ +export const byIndex = (ast: ESQLAstQueryExpression, index: number): ESQLCommand | undefined => { + return [...list(ast)][index]; +}; + +/** + * Summary of a STATS command. + */ +export interface StatsCommandSummary { + /** + * The "STATS" command AST node from which this summary was produced. + */ + command: ESQLCommand; + + /** + * Summary of the main arguments of the "STATS" command. + */ + aggregates: Record; + + /** + * Summary of the "BY" arguments of the "STATS" command. + */ + grouping: Record; + + /** + * De-duplicated list all of ES|QL-syntax formatted field names from the + * {@link aggregates} and {@link grouping} fields. + */ + fields: Set; +} + +/** + * Summary of STATS command "aggregates" section (main arguments). + * + * STATS [ BY ] + */ +export interface StatsAggregatesSummary { + /** + * STATS command argument AST node (as was parsed). + */ + arg: ESQLProperNode; + + /** + * The field name, correctly formatted, extracted from the AST. + */ + field: string; + + /** + * A `column` AST node, which represents the field name. If no column AST node + * was found, a new one "virtual" column node is created. + */ + column: ESQLColumn; + + /** + * The definition of the field, which is the right-hand side of the `=` + * operator, or the argument itself if no `=` operator is present. + */ + definition: ESQLProperNode; + + /** + * A list of terminal nodes that were found in the definition. + */ + terminals: Array; + + /** + * Correctly formatted list of field names that were found in the {@link terminals}. + */ + fields: string[]; +} + +const summarizeArgParts = ( + query: EsqlQuery, + arg: ESQLProperNode +): [column: ESQLColumn, definition: ESQLProperNode] => { + if (isFunctionExpression(arg) && arg.name === '=' && isColumn(arg.args[0])) { + const [column, definition] = singleItems(arg.args); + + return [column as ESQLColumn, definition as ESQLProperNode]; + } + + const name = [...query.src].slice(arg.location.min, arg.location.max + 1).join(''); + const args = [Builder.identifier({ name })]; + const column = Builder.expression.column({ args }); + + return [column, arg]; +}; + +const summarizeArg = (query: EsqlQuery, arg: ESQLProperNode): StatsAggregatesSummary => { + const [column, definition] = summarizeArgParts(query, arg); + const terminals: StatsAggregatesSummary['terminals'] = []; + const fields: StatsAggregatesSummary['fields'] = []; + + Walker.walk(definition, { + visitLiteral(node) { + terminals.push(node); + }, + visitColumn(node) { + terminals.push(node); + fields.push(LeafPrinter.column(node)); + }, + visitListLiteral(node) { + terminals.push(node); + }, + visitTimeIntervalLiteral(node) { + terminals.push(node); + }, + }); + + const summary: StatsAggregatesSummary = { + arg, + field: LeafPrinter.column(column), + column, + definition, + terminals, + fields, + }; + + return summary; +}; + +/** + * Returns a summary of the STATS command. + * + * @param query Query which contains the AST and source code. + * @param command The STATS command AST node to summarize. + * @returns Summary of the STATS command. + */ +export const summarizeCommand = (query: EsqlQuery, command: ESQLCommand): StatsCommandSummary => { + const aggregates: StatsCommandSummary['aggregates'] = {}; + const grouping: StatsCommandSummary['grouping'] = {}; + const fields: StatsCommandSummary['fields'] = new Set(); + + // Process main arguments, the "aggregates" part of the command. + new Visitor() + .on('visitExpression', (ctx) => { + const summary = summarizeArg(query, ctx.node); + aggregates[summary.field] = summary; + for (const field of summary.fields) fields.add(field); + }) + .on('visitCommand', () => {}) + .on('visitStatsCommand', (ctx) => { + for (const _ of ctx.visitArguments()); + }) + .visitCommand(command); + + // Process the "BY" arguments, the "grouping" part of the command. + new Visitor() + .on('visitExpression', () => {}) + .on('visitColumnExpression', (ctx) => { + const column = ctx.node; + const formatted = LeafPrinter.column(column); + grouping[formatted] = column; + fields.add(formatted); + }) + .on('visitCommandOption', (ctx) => { + if (ctx.node.name !== 'by') return; + for (const _ of ctx.visitArguments()); + }) + .on('visitCommand', () => {}) + .on('visitStatsCommand', (ctx) => { + for (const _ of ctx.visitOptions()); + }) + .visitCommand(command); + + const summary: StatsCommandSummary = { + command, + aggregates, + grouping, + fields, + }; + + return summary; +}; + +/** + * Summarizes all STATS commands in the query. + * + * @param query Query to summarize. + * @returns Returns a list of summaries for all STATS commands in the query in + * order of appearance. + */ +export const summarize = (query: EsqlQuery): StatsCommandSummary[] => { + const summaries: StatsCommandSummary[] = []; + + for (const command of list(query.ast)) { + const summary = summarizeCommand(query, command); + summaries.push(summary); + } + + return summaries; +}; diff --git a/packages/kbn-esql-ast/src/parser/__tests__/columns.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/columns.test.ts index 38e98104d41b..f235005a2c10 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/columns.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/columns.test.ts @@ -10,21 +10,86 @@ import { parse } from '..'; describe('Column Identifier Expressions', () => { + it('can parse star column as function argument', () => { + const text = 'ROW fn(*)'; + const { root } = parse(text); + + expect(root.commands).toMatchObject([ + { + type: 'command', + name: 'row', + args: [ + { + type: 'function', + name: 'fn', + args: [ + { + type: 'column', + args: [ + { + type: 'identifier', + name: '*', + }, + ], + }, + ], + }, + ], + }, + ]); + }); + + it('can parse a single identifier', () => { + const text = 'ROW hello'; + const { root } = parse(text); + + expect(root.commands).toMatchObject([ + { + type: 'command', + args: [ + { + type: 'column', + args: [ + { + type: 'identifier', + name: 'hello', + }, + ], + }, + ], + }, + ]); + }); + it('can parse un-quoted identifiers', () => { const text = 'ROW a, b.c'; - const { ast } = parse(text); + const { root } = parse(text); - expect(ast).toMatchObject([ + expect(root.commands).toMatchObject([ { type: 'command', args: [ { type: 'column', - parts: ['a'], + args: [ + { + type: 'identifier', + name: 'a', + }, + ], }, { type: 'column', - parts: ['b', 'c'], + args: [ + { + type: 'identifier', + name: 'b', + }, + { + type: 'identifier', + name: 'c', + }, + ], }, ], }, @@ -33,23 +98,50 @@ describe('Column Identifier Expressions', () => { it('can parse quoted identifiers', () => { const text = 'ROW `a`, `b`.c, `d`.`👍`.`123``123`'; - const { ast } = parse(text); + const { root } = parse(text); - expect(ast).toMatchObject([ + expect(root.commands).toMatchObject([ { type: 'command', args: [ { type: 'column', - parts: ['a'], + args: [ + { + type: 'identifier', + name: 'a', + }, + ], }, { type: 'column', - parts: ['b', 'c'], + args: [ + { + type: 'identifier', + name: 'b', + }, + { + type: 'identifier', + name: 'c', + }, + ], }, { type: 'column', - parts: ['d', '👍', '123`123'], + args: [ + { + type: 'identifier', + name: 'd', + }, + { + type: 'identifier', + name: '👍', + }, + { + type: 'identifier', + name: '123`123', + }, + ], }, ], }, @@ -58,15 +150,28 @@ describe('Column Identifier Expressions', () => { it('can mix quoted and un-quoted identifiers', () => { const text = 'ROW part1.part2.`part``3️⃣`'; - const { ast } = parse(text); + const { root } = parse(text); - expect(ast).toMatchObject([ + expect(root.commands).toMatchObject([ { type: 'command', args: [ { type: 'column', - parts: ['part1', 'part2', 'part`3️⃣'], + args: [ + { + type: 'identifier', + name: 'part1', + }, + { + type: 'identifier', + name: 'part2', + }, + { + type: 'identifier', + name: 'part`3️⃣', + }, + ], }, ], }, @@ -75,19 +180,189 @@ describe('Column Identifier Expressions', () => { it('in KEEP command', () => { const text = 'FROM a | KEEP a.b'; - const { ast } = parse(text); + const { root } = parse(text); - expect(ast).toMatchObject([ + expect(root.commands).toMatchObject([ {}, { type: 'command', args: [ { type: 'column', - parts: ['a', 'b'], + args: [ + { + type: 'identifier', + name: 'a', + }, + { + type: 'identifier', + name: 'b', + }, + ], }, ], }, ]); }); + + describe('params', () => { + it('can parse named param as a single param node', () => { + const text = 'ROW ?test'; + const { root } = parse(text); + + expect(root.commands).toMatchObject([ + { + type: 'command', + args: [ + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'test', + }, + ], + }, + ]); + }); + + it('can parse nested named params as column', () => { + const text = 'ROW ?test1.?test2'; + const { root } = parse(text); + + expect(root.commands).toMatchObject([ + { + type: 'command', + args: [ + { + type: 'column', + args: [ + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'test1', + }, + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'test2', + }, + ], + }, + ], + }, + ]); + }); + + it('can mix param and identifier in column name', () => { + const text = 'ROW ?par.id'; + const { root } = parse(text); + + expect(root.commands).toMatchObject([ + { + type: 'command', + args: [ + { + type: 'column', + args: [ + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'par', + }, + { + type: 'identifier', + name: 'id', + }, + ], + }, + ], + }, + ]); + }); + + it('can mix param and identifier in column name - 2', () => { + const text = 'ROW `😱`.?par'; + const { root } = parse(text); + + expect(root.commands).toMatchObject([ + { + type: 'command', + args: [ + { + type: 'column', + args: [ + { + type: 'identifier', + name: '😱', + }, + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'par', + }, + ], + }, + ], + }, + ]); + }); + + it('supports all three different param types', () => { + const text = 'ROW ?.?name.?123'; + const { root } = parse(text); + + expect(root.commands).toMatchObject([ + { + type: 'command', + args: [ + { + type: 'column', + args: [ + { + type: 'literal', + literalType: 'param', + paramType: 'unnamed', + }, + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'name', + }, + { + type: 'literal', + literalType: 'param', + paramType: 'positional', + value: 123, + }, + ], + }, + ], + }, + ]); + }); + + it('parses DROP command args as "column" nodes', () => { + const text = 'FROM index | DROP any#Char$Field'; + const { root } = parse(text); + + expect(root.commands).toMatchObject([ + { type: 'command' }, + { + type: 'command', + name: 'drop', + args: [ + { + type: 'column', + name: 'any', + }, + ], + }, + ]); + }); + }); }); diff --git a/packages/kbn-esql-ast/src/parser/__tests__/function.test.ts b/packages/kbn-esql-ast/src/parser/__tests__/function.test.ts index d05ed36204b1..486feae97f98 100644 --- a/packages/kbn-esql-ast/src/parser/__tests__/function.test.ts +++ b/packages/kbn-esql-ast/src/parser/__tests__/function.test.ts @@ -8,6 +8,7 @@ */ import { parse } from '..'; +import { EsqlQuery } from '../../query'; import { Walker } from '../../walker'; describe('function AST nodes', () => { @@ -323,3 +324,86 @@ describe('function AST nodes', () => { }); }); }); + +describe('location', () => { + const getFunctionTexts = (src: string) => { + const query = EsqlQuery.fromSrc(src); + const functions = Walker.matchAll(query.ast, { type: 'function' }); + const texts: string[] = functions.map((fn) => { + return [...src].slice(fn.location.min, fn.location.max + 1).join(''); + }); + + return texts; + }; + + it('correctly cuts out function source texts', () => { + const texts = getFunctionTexts( + 'FROM index | LIMIT 1 | STATS agg() | LIMIT 2 | STATS max(a, b, c), max2(d.e)' + ); + + expect(texts).toEqual(['agg()', 'max(a, b, c)', 'max2(d.e)']); + }); + + it('functions in binary expressions', () => { + const texts = getFunctionTexts('FROM index | STATS foo = agg(f1) + agg(f2), a.b = agg(f3)'); + + expect(texts).toEqual([ + 'foo = agg(f1) + agg(f2)', + 'agg(f1) + agg(f2)', + 'agg(f1)', + 'agg(f2)', + 'a.b = agg(f3)', + 'agg(f3)', + ]); + }); + + it('with the simplest comment after function name identifier', () => { + const texts1 = getFunctionTexts('FROM index | STATS agg/* */(1)'); + expect(texts1).toEqual(['agg/* */(1)']); + + const texts2 = getFunctionTexts('FROM index | STATS agg/* A */(a)'); + expect(texts2).toEqual(['agg/* A */(a)']); + + const texts3 = getFunctionTexts('FROM index | STATS agg /* A */ (*)'); + expect(texts3).toEqual(['agg /* A */ (*)']); + }); + + it('with the simplest emoji comment after function name identifier', () => { + const texts = getFunctionTexts('FROM index | STATS agg/* 😎 */(*)'); + expect(texts).toEqual(['agg/* 😎 */(*)']); + }); + + it('with the simplest emoji comment after function name identifier, followed by another arg', () => { + const texts = getFunctionTexts('FROM index | STATS agg/* 😎 */(*), abc'); + expect(texts).toEqual(['agg/* 😎 */(*)']); + }); + + it('simple emoji comment twice', () => { + const texts = getFunctionTexts('FROM index | STATS agg/* 😎 */(*), max/* 😎 */(*)'); + expect(texts).toEqual(['agg/* 😎 */(*)', 'max/* 😎 */(*)']); + }); + + it('with comment and emoji after function name identifier', () => { + const texts = getFunctionTexts('FROM index | STATS agg /* haha 😅 */ (*)'); + + expect(texts).toEqual(['agg /* haha 😅 */ (*)']); + }); + + it('with comment inside argument list', () => { + const texts = getFunctionTexts('FROM index | STATS agg ( /* haha 😅 */ )'); + + expect(texts).toEqual(['agg ( /* haha 😅 */ )']); + }); + + it('with emoji and comment in argument lists', () => { + const texts = getFunctionTexts( + 'FROM index | STATS agg( /* haha 😅 */ max(foo), bar, baz), test( /* asdf */ * /* asdf */)' + ); + + expect(texts).toEqual([ + 'agg( /* haha 😅 */ max(foo), bar, baz)', + 'max(foo)', + 'test( /* asdf */ * /* asdf */)', + ]); + }); +}); diff --git a/packages/kbn-esql-ast/src/parser/factories.ts b/packages/kbn-esql-ast/src/parser/factories.ts index b575447f7e74..311dcced8a61 100644 --- a/packages/kbn-esql-ast/src/parser/factories.ts +++ b/packages/kbn-esql-ast/src/parser/factories.ts @@ -31,6 +31,7 @@ import { IdentifierContext, InputParamContext, InputNamedOrPositionalParamContext, + IdentifierOrParameterContext, } from '../antlr/esql_parser'; import { DOUBLE_TICKS_REGEX, SINGLE_BACKTICK, TICKS_REGEX } from './constants'; import type { @@ -227,26 +228,35 @@ export const createFunctionCall = (ctx: FunctionContext): ESQLFunctionCallExpres }; const identifierOrParameter = functionName.identifierOrParameter(); - if (identifierOrParameter) { - const identifier = identifierOrParameter.identifier(); - if (identifier) { - node.operator = createIdentifier(identifier); - } else { - const parameter = identifierOrParameter.parameter(); - if (parameter) { - node.operator = createParam(parameter); - } + + if (identifierOrParameter instanceof IdentifierOrParameterContext) { + const operator = createIdentifierOrParam(identifierOrParameter); + + if (operator) { + node.operator = operator; } } return node; }; -const createIdentifier = (identifier: IdentifierContext): ESQLIdentifier => { - return Builder.identifier( - { name: identifier.getText().toLowerCase() }, - createParserFields(identifier) - ); +export const createIdentifierOrParam = (ctx: IdentifierOrParameterContext) => { + const identifier = ctx.identifier(); + if (identifier) { + return createIdentifier(identifier); + } else { + const parameter = ctx.parameter(); + if (parameter) { + return createParam(parameter); + } + } +}; + +export const createIdentifier = (identifier: IdentifierContext): ESQLIdentifier => { + const text = identifier.getText(); + const name = parseIdentifier(text); + + return Builder.identifier({ name }, createParserFields(identifier)); }; export const createParam = (ctx: ParseTree) => { @@ -473,42 +483,68 @@ export function createSource( export function createColumnStar(ctx: TerminalNode): ESQLColumn { const text = ctx.getText(); - - return { - type: 'column', - name: text, - parts: [text], + const parserFields = { text, location: getPosition(ctx.symbol), incomplete: ctx.getText() === '', quoted: false, }; + const node = Builder.expression.column( + { args: [Builder.identifier({ name: '*' }, parserFields)] }, + parserFields + ); + + node.name = text; + + return node; } export function createColumn(ctx: ParserRuleContext): ESQLColumn { - const parts: string[] = []; + const args: ESQLColumn['args'] = []; + if (ctx instanceof QualifiedNamePatternContext) { - parts.push( - ...ctx.identifierPattern_list().map((identifier) => parseIdentifier(identifier.getText())) - ); + const list = ctx.identifierPattern_list(); + + for (const identifier of list) { + const name = parseIdentifier(identifier.getText()); + const node = Builder.identifier({ name }, createParserFields(identifier)); + + args.push(node); + } } else if (ctx instanceof QualifiedNameContext) { - parts.push( - ...ctx.identifierOrParameter_list().map((identifier) => parseIdentifier(identifier.getText())) - ); + const list = ctx.identifierOrParameter_list(); + + for (const item of list) { + if (item instanceof IdentifierOrParameterContext) { + const node = createIdentifierOrParam(item); + + if (node) { + args.push(node); + } + } + } } else { - parts.push(sanitizeIdentifierString(ctx)); + const name = sanitizeIdentifierString(ctx); + const node = Builder.identifier({ name }, createParserFields(ctx)); + + args.push(node); } + const text = sanitizeIdentifierString(ctx); const hasQuotes = Boolean(getQuotedText(ctx) || isQuoted(ctx.getText())); - return { - type: 'column' as const, - name: text, - parts, - text: ctx.getText(), - location: getPosition(ctx.start, ctx.stop), - incomplete: Boolean(ctx.exception || text === ''), - quoted: hasQuotes, - }; + const column = Builder.expression.column( + { args }, + { + text: ctx.getText(), + location: getPosition(ctx.start, ctx.stop), + incomplete: Boolean(ctx.exception || text === ''), + } + ); + + column.name = text; + column.quoted = hasQuotes; + + return column; } export function createOption(name: string, ctx: ParserRuleContext): ESQLCommandOption { diff --git a/packages/kbn-esql-ast/src/parser/helpers.ts b/packages/kbn-esql-ast/src/parser/helpers.ts index f11cb396f298..528176684418 100644 --- a/packages/kbn-esql-ast/src/parser/helpers.ts +++ b/packages/kbn-esql-ast/src/parser/helpers.ts @@ -41,17 +41,16 @@ export const formatIdentifierParts = (parts: string[]): string => parts.map(formatIdentifier).join('.'); export const getPosition = ( - token: Pick | null, - lastToken?: Pick | undefined + start: Pick | null, + stop?: Pick | undefined ) => { - if (!token || token.start < 0) { + if (!start || start.start < 0) { return { min: 0, max: 0 }; } - const endFirstToken = token.stop > -1 ? Math.max(token.stop + 1, token.start) : undefined; - const endLastToken = lastToken?.stop; + const endFirstToken = start.stop > -1 ? Math.max(start.stop + 1, start.start) : undefined; return { - min: token.start, - max: endLastToken ?? endFirstToken ?? Infinity, + min: start.start, + max: stop?.stop ?? endFirstToken ?? Infinity, }; }; diff --git a/packages/kbn-esql-ast/src/pretty_print/__tests__/basic_pretty_printer.test.ts b/packages/kbn-esql-ast/src/pretty_print/__tests__/basic_pretty_printer.test.ts index 9e21c45f75b4..c8880b9bfe67 100644 --- a/packages/kbn-esql-ast/src/pretty_print/__tests__/basic_pretty_printer.test.ts +++ b/packages/kbn-esql-ast/src/pretty_print/__tests__/basic_pretty_printer.test.ts @@ -78,15 +78,6 @@ describe('single line query', () => { }); }); - describe('SHOW', () => { - /** @todo Enable once show command args are parsed as columns. */ - test.skip('info page', () => { - const { text } = reprint('SHOW info'); - - expect(text).toBe('SHOW info'); - }); - }); - describe('STATS', () => { test('with aggregates assignment', () => { const { text } = reprint('FROM a | STATS var = agg(123, fn(true))'); @@ -100,6 +91,30 @@ describe('single line query', () => { expect(text).toBe('FROM a | STATS A(1), B(2) BY asdf'); }); }); + + describe('GROK', () => { + test('two basic arguments', () => { + const { text } = reprint('FROM search-movies | GROK Awards "text"'); + + expect(text).toBe('FROM search-movies | GROK Awards "text"'); + }); + }); + + describe('DISSECT', () => { + test('two basic arguments', () => { + const { text } = reprint('FROM index | DISSECT input "pattern"'); + + expect(text).toBe('FROM index | DISSECT input "pattern"'); + }); + + test('with APPEND_SEPARATOR option', () => { + const { text } = reprint( + 'FROM index | DISSECT input "pattern" APPEND_SEPARATOR=""' + ); + + expect(text).toBe('FROM index | DISSECT input "pattern" APPEND_SEPARATOR = ""'); + }); + }); }); describe('expressions', () => { diff --git a/packages/kbn-esql-ast/src/pretty_print/__tests__/wrapping_pretty_printer.test.ts b/packages/kbn-esql-ast/src/pretty_print/__tests__/wrapping_pretty_printer.test.ts index 2dfe239ce5b8..6422ae9a451a 100644 --- a/packages/kbn-esql-ast/src/pretty_print/__tests__/wrapping_pretty_printer.test.ts +++ b/packages/kbn-esql-ast/src/pretty_print/__tests__/wrapping_pretty_printer.test.ts @@ -19,6 +19,83 @@ const reprint = (src: string, opts?: WrappingPrettyPrinterOptions) => { return { text }; }; +describe('commands', () => { + describe('GROK', () => { + test('two basic arguments', () => { + const { text } = reprint('FROM search-movies | GROK Awards "text"'); + + expect(text).toBe('FROM search-movies | GROK Awards "text"'); + }); + + test('two long arguments', () => { + const { text } = reprint( + 'FROM search-movies | GROK AwardsAwardsAwardsAwardsAwardsAwardsAwardsAwards "texttexttexttexttexttexttexttexttexttexttexttexttexttexttext"' + ); + + expect('\n' + text).toBe(` +FROM search-movies + | GROK + AwardsAwardsAwardsAwardsAwardsAwardsAwardsAwards + "texttexttexttexttexttexttexttexttexttexttexttexttexttexttext"`); + }); + }); + + describe('DISSECT', () => { + test('two basic arguments', () => { + const { text } = reprint('FROM index | DISSECT input "pattern"'); + + expect(text).toBe('FROM index | DISSECT input "pattern"'); + }); + + test('two long arguments', () => { + const { text } = reprint( + 'FROM index | DISSECT InputInputInputInputInputInputInputInputInputInputInputInputInputInput "PatternPatternPatternPatternPatternPatternPatternPatternPatternPattern"' + ); + + expect('\n' + text).toBe(` +FROM index + | DISSECT + InputInputInputInputInputInputInputInputInputInputInputInputInputInput + "PatternPatternPatternPatternPatternPatternPatternPatternPatternPattern"`); + }); + + test('with APPEND_SEPARATOR option', () => { + const { text } = reprint( + 'FROM index | DISSECT input "pattern" APPEND_SEPARATOR=""' + ); + + expect(text).toBe('FROM index | DISSECT input "pattern" APPEND_SEPARATOR = ""'); + }); + + test('two long arguments with short APPEND_SEPARATOR option', () => { + const { text } = reprint( + 'FROM index | DISSECT InputInputInputInputInputInputInputInputInputInputInputInputInputInput "PatternPatternPatternPatternPatternPatternPatternPatternPatternPattern" APPEND_SEPARATOR="sep"' + ); + + expect('\n' + text).toBe(` +FROM index + | DISSECT + InputInputInputInputInputInputInputInputInputInputInputInputInputInput + "PatternPatternPatternPatternPatternPatternPatternPatternPatternPattern" + APPEND_SEPARATOR = "sep"`); + }); + + test('two long arguments with long APPEND_SEPARATOR option', () => { + const { text } = reprint( + 'FROM index | DISSECT InputInputInputInputInputInputInputInputInputInputInputInputInputInput "PatternPatternPatternPatternPatternPatternPatternPatternPatternPattern" APPEND_SEPARATOR=""' + ); + + expect('\n' + text).toBe(` +FROM index + | DISSECT + InputInputInputInputInputInputInputInputInputInputInputInputInputInput + "PatternPatternPatternPatternPatternPatternPatternPatternPatternPattern" + APPEND_SEPARATOR = + ""`); + }); + }); +}); + describe('casing', () => { test('can chose command name casing', () => { const query = 'FROM index | WHERE a == 123'; diff --git a/packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts b/packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts index 2f1e3439cd3a..cf252825c243 100644 --- a/packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts +++ b/packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts @@ -19,6 +19,7 @@ import { import { ESQLAstBaseItem, ESQLAstCommand, ESQLAstQueryExpression } from '../types'; import { ESQLAstExpressionNode, Visitor } from '../visitor'; import { resolveItem } from '../visitor/utils'; +import { commandOptionsWithEqualsSeparator, commandsWithNoCommaArgSeparator } from './constants'; import { LeafPrinter } from './leaf_printer'; export interface BasicPrettyPrinterOptions { @@ -378,7 +379,8 @@ export class BasicPrettyPrinter { args += (args ? ', ' : '') + arg; } - const argsFormatted = args ? ` ${args}` : ''; + const separator = commandOptionsWithEqualsSeparator.has(ctx.node.name) ? ' = ' : ' '; + const argsFormatted = args ? `${separator}${args}` : ''; const optionFormatted = `${option}${argsFormatted}`; return optionFormatted; @@ -392,7 +394,10 @@ export class BasicPrettyPrinter { let options = ''; for (const source of ctx.visitArguments()) { - args += (args ? ', ' : '') + source; + const needsSeparator = !!args; + const needsComma = !commandsWithNoCommaArgSeparator.has(ctx.node.name); + const separator = needsSeparator ? (needsComma ? ',' : '') + ' ' : ''; + args += separator + source; } for (const option of ctx.visitOptions()) { diff --git a/packages/kbn-esql-ast/src/pretty_print/constants.ts b/packages/kbn-esql-ast/src/pretty_print/constants.ts new file mode 100644 index 000000000000..01208af98d02 --- /dev/null +++ b/packages/kbn-esql-ast/src/pretty_print/constants.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", 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". + */ + +/** + * This set tracks commands that don't use commas to separate their + * arguments. + * + * Normally ES|QL command arguments are separated by commas. + * + * ``` + * COMMAND arg1, arg2, arg3 + * ``` + * + * But there are some commands (namely `grok` and `dissect`) which don't + * use commas to separate their arguments. + * + * ``` + * GROK input "pattern" + * DISSECT input "pattern" + * ``` + */ +export const commandsWithNoCommaArgSeparator = new Set(['grok', 'dissect']); + +/** + * This set tracks command options which use an equals sign to separate + * the option label from the option value. + * + * Most ES|QL commands use a space to separate the option label from the + * option value. + * + * ``` + * COMMAND arg1, arg2, arg3 OPTION option + * FROM index METADATA _id + * ``` + * + * However, the `APPEND_SEPARATOR` in the `DISSECT` command uses an equals + * sign to separate the option label from the option value. + * + * ``` + * DISSECT input "pattern" APPEND_SEPARATOR = "separator" + * | + * | + * equals sign + * ``` + */ +export const commandOptionsWithEqualsSeparator = new Set(['append_separator']); diff --git a/packages/kbn-esql-ast/src/pretty_print/leaf_printer.ts b/packages/kbn-esql-ast/src/pretty_print/leaf_printer.ts index 3c12de90e445..b413234cbe26 100644 --- a/packages/kbn-esql-ast/src/pretty_print/leaf_printer.ts +++ b/packages/kbn-esql-ast/src/pretty_print/leaf_printer.ts @@ -12,6 +12,7 @@ import { ESQLAstCommentMultiLine, ESQLColumn, ESQLLiteral, + ESQLParamLiteral, ESQLSource, ESQLTimeInterval, } from '../types'; @@ -27,20 +28,37 @@ export const LeafPrinter = { source: (node: ESQLSource) => node.name, column: (node: ESQLColumn) => { - const parts: string[] = node.parts; + const args = node.args; let formatted = ''; - for (const part of parts) { - if (formatted.length > 0) { - formatted += '.'; - } - if (regexUnquotedIdPattern.test(part)) { - formatted += part; - } else { - // Escape backticks "`" with double backticks "``". - const escaped = part.replace(/`/g, '``'); - formatted += '`' + escaped + '`'; + for (const arg of args) { + switch (arg.type) { + case 'identifier': { + const name = arg.name; + + if (formatted.length > 0) { + formatted += '.'; + } + if (regexUnquotedIdPattern.test(name)) { + formatted += name; + } else { + // Escape backticks "`" with double backticks "``". + const escaped = name.replace(/`/g, '``'); + formatted += '`' + escaped + '`'; + } + + break; + } + case 'literal': { + if (formatted.length > 0) { + formatted += '.'; + } + + formatted += LeafPrinter.literal(arg); + + break; + } } } @@ -56,13 +74,7 @@ export const LeafPrinter = { return String(node.value).toUpperCase() === 'TRUE' ? 'TRUE' : 'FALSE'; } case 'param': { - switch (node.paramType) { - case 'named': - case 'positional': - return '?' + node.value; - default: - return '?'; - } + return LeafPrinter.param(node); } case 'keyword': { return String(node.value); @@ -82,6 +94,16 @@ export const LeafPrinter = { } }, + param: (node: ESQLParamLiteral) => { + switch (node.paramType) { + case 'named': + case 'positional': + return '?' + node.value; + default: + return '?'; + } + }, + timeInterval: (node: ESQLTimeInterval) => { const { quantity, unit } = node; diff --git a/packages/kbn-esql-ast/src/pretty_print/wrapping_pretty_printer.ts b/packages/kbn-esql-ast/src/pretty_print/wrapping_pretty_printer.ts index 91f65a389f0c..2f863524740e 100644 --- a/packages/kbn-esql-ast/src/pretty_print/wrapping_pretty_printer.ts +++ b/packages/kbn-esql-ast/src/pretty_print/wrapping_pretty_printer.ts @@ -20,6 +20,7 @@ import { } from '../visitor'; import { children, singleItems } from '../visitor/utils'; import { BasicPrettyPrinter, BasicPrettyPrinterOptions } from './basic_pretty_printer'; +import { commandOptionsWithEqualsSeparator, commandsWithNoCommaArgSeparator } from './constants'; import { getPrettyPrintStats } from './helpers'; import { LeafPrinter } from './leaf_printer'; @@ -259,6 +260,8 @@ export class WrappingPrettyPrinter { } } + const commaBetweenArgs = !commandsWithNoCommaArgSeparator.has(ctx.node.name); + if (!oneArgumentPerLine) { ARGS: for (const arg of singleItems(ctx.arguments())) { if (arg.type === 'option') { @@ -271,7 +274,8 @@ export class WrappingPrettyPrinter { if (formattedArgLength > largestArg) { largestArg = formattedArgLength; } - let separator = txt ? ',' : ''; + + let separator = txt ? (commaBetweenArgs ? ',' : '') : ''; let fragment = ''; if (needsWrap) { @@ -329,7 +333,7 @@ export class WrappingPrettyPrinter { const arg = ctx.visitExpression(args[i], { indent, remaining: this.opts.wrap - indent.length, - suffix: isLastArg ? '' : ',', + suffix: isLastArg ? '' : commaBetweenArgs ? ',' : '', }); const separator = isFirstArg ? '' : '\n'; const indentation = arg.indented ? '' : indent; @@ -557,8 +561,9 @@ export class WrappingPrettyPrinter { indent: inp.indent, remaining: inp.remaining - option.length - 1, }); - const argsFormatted = args.txt ? ` ${args.txt}` : ''; - const txt = `${option}${argsFormatted}`; + const argsFormatted = args.txt ? `${args.txt[0] === '\n' ? '' : ' '}${args.txt}` : ''; + const separator = commandOptionsWithEqualsSeparator.has(ctx.node.name) ? ' =' : ''; + const txt = `${option}${separator}${argsFormatted}`; return { txt, lines: args.lines }; }) diff --git a/packages/kbn-esql-ast/src/query/query.ts b/packages/kbn-esql-ast/src/query/query.ts index 60435cc64c97..66c9fd58df08 100644 --- a/packages/kbn-esql-ast/src/query/query.ts +++ b/packages/kbn-esql-ast/src/query/query.ts @@ -15,6 +15,10 @@ import { WrappingPrettyPrinterOptions, } from '../pretty_print/wrapping_pretty_printer'; +/** + * Represents a parsed or programmatically created ES|QL query. Keeps track of + * the AST, source code, and optionally lexer tokens. + */ export class EsqlQuery { public static readonly fromSrc = (src: string, opts?: ParseOptions): EsqlQuery => { const { root, tokens } = parse(src, opts); diff --git a/packages/kbn-esql-ast/src/types.ts b/packages/kbn-esql-ast/src/types.ts index ea76fc3e0b9a..2a8513fc2ced 100644 --- a/packages/kbn-esql-ast/src/types.ts +++ b/packages/kbn-esql-ast/src/types.ts @@ -276,6 +276,15 @@ export interface ESQLSource extends ESQLAstBaseItem { export interface ESQLColumn extends ESQLAstBaseItem { type: 'column'; + /** + * A ES|QL column name can be composed of multiple parts, + * e.g: part1.part2.`part``3️⃣`.?param. Where parts can be quoted, or not + * quoted, or even be a parameter. + * + * The args list contains the parts of the column name. + */ + args: Array; + /** * An identifier can be composed of multiple parts, e.g: part1.part2.`part``3️⃣`. * This property contains the parsed unquoted parts of the identifier. diff --git a/packages/kbn-esql-ast/src/walker/walker.test.ts b/packages/kbn-esql-ast/src/walker/walker.test.ts index 980e1499e62a..49c50a0f7fa5 100644 --- a/packages/kbn-esql-ast/src/walker/walker.test.ts +++ b/packages/kbn-esql-ast/src/walker/walker.test.ts @@ -812,6 +812,112 @@ describe('Walker.params()', () => { }, ]); }); + + test('can collect params from column names', () => { + const query = 'ROW ?a.?b'; + const { ast } = parse(query); + const params = Walker.params(ast); + + expect(params).toMatchObject([ + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'a', + }, + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'b', + }, + ]); + }); + + test('can collect params from column names, where first part is not a param', () => { + const query = 'ROW a.?b'; + const { ast } = parse(query); + const params = Walker.params(ast); + + expect(params).toMatchObject([ + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'b', + }, + ]); + }); + + test('can collect all types of param from column name', () => { + const query = 'ROW ?.?0.?a'; + const { ast } = parse(query); + const params = Walker.params(ast); + + expect(params).toMatchObject([ + { + type: 'literal', + literalType: 'param', + paramType: 'unnamed', + }, + { + type: 'literal', + literalType: 'param', + paramType: 'positional', + value: 0, + }, + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'a', + }, + ]); + }); + + test('can collect params from function names', () => { + const query = 'FROM a | STATS ?lala()'; + const { ast } = parse(query); + const params = Walker.params(ast); + + expect(params).toMatchObject([ + { + type: 'literal', + literalType: 'param', + paramType: 'named', + value: 'lala', + }, + ]); + }); + + test('can collect params from function names (unnamed)', () => { + const query = 'FROM a | STATS ?()'; + const { ast } = parse(query); + const params = Walker.params(ast); + + expect(params).toMatchObject([ + { + type: 'literal', + literalType: 'param', + paramType: 'unnamed', + }, + ]); + }); + + test('can collect params from function names (positional)', () => { + const query = 'FROM a | STATS agg(test), ?123()'; + const { ast } = parse(query); + const params = Walker.params(ast); + + expect(params).toMatchObject([ + { + type: 'literal', + literalType: 'param', + paramType: 'positional', + value: 123, + }, + ]); + }); }); describe('Walker.find()', () => { diff --git a/packages/kbn-esql-ast/src/walker/walker.ts b/packages/kbn-esql-ast/src/walker/walker.ts index dbbbc3b090f2..f3b6de91649b 100644 --- a/packages/kbn-esql-ast/src/walker/walker.ts +++ b/packages/kbn-esql-ast/src/walker/walker.ts @@ -20,6 +20,7 @@ import type { ESQLCommandMode, ESQLCommandOption, ESQLFunction, + ESQLIdentifier, ESQLInlineCast, ESQLList, ESQLLiteral, @@ -49,6 +50,7 @@ export interface WalkerOptions { visitTimeIntervalLiteral?: (node: ESQLTimeInterval) => void; visitInlineCast?: (node: ESQLInlineCast) => void; visitUnknown?: (node: ESQLUnknownItem) => void; + visitIdentifier?: (node: ESQLIdentifier) => void; /** * Called for any node type that does not have a specific visitor. @@ -346,11 +348,27 @@ export class Walker { } } + public walkColumn(node: ESQLColumn): void { + const { options } = this; + const { args } = node; + + (options.visitColumn ?? options.visitAny)?.(node); + + if (args) { + for (const value of args) { + this.walkAstItem(value); + } + } + } + public walkFunction(node: ESQLFunction): void { const { options } = this; (options.visitFunction ?? options.visitAny)?.(node); const args = node.args; const length = args.length; + + if (node.operator) this.walkAstItem(node.operator); + for (let i = 0; i < length; i++) { const arg = args[i]; this.walkAstItem(arg); @@ -393,7 +411,7 @@ export class Walker { break; } case 'column': { - (options.visitColumn ?? options.visitAny)?.(node); + this.walkColumn(node); break; } case 'literal': { @@ -412,6 +430,10 @@ export class Walker { (options.visitInlineCast ?? options.visitAny)?.(node); break; } + case 'identifier': { + (options.visitIdentifier ?? options.visitAny)?.(node); + break; + } case 'unknown': { (options.visitUnknown ?? options.visitAny)?.(node); break; diff --git a/packages/kbn-esql-utils/index.ts b/packages/kbn-esql-utils/index.ts index ee47c0321e2e..9519e84624cb 100644 --- a/packages/kbn-esql-utils/index.ts +++ b/packages/kbn-esql-utils/index.ts @@ -31,6 +31,7 @@ export { getQueryColumnsFromESQLQuery, isESQLColumnSortable, isESQLColumnGroupable, + isESQLFieldGroupable, TextBasedLanguages, } from './src'; diff --git a/packages/kbn-esql-utils/src/index.ts b/packages/kbn-esql-utils/src/index.ts index cf530be20d7a..6cf2dd031bf0 100644 --- a/packages/kbn-esql-utils/src/index.ts +++ b/packages/kbn-esql-utils/src/index.ts @@ -31,4 +31,8 @@ export { getStartEndParams, hasStartEndParams, } from './utils/run_query'; -export { isESQLColumnSortable, isESQLColumnGroupable } from './utils/esql_fields_utils'; +export { + isESQLColumnSortable, + isESQLColumnGroupable, + isESQLFieldGroupable, +} from './utils/esql_fields_utils'; diff --git a/packages/kbn-esql-utils/src/utils/esql_fields_utils.test.ts b/packages/kbn-esql-utils/src/utils/esql_fields_utils.test.ts index bfc3a4d6708f..5bf9980d4ae7 100644 --- a/packages/kbn-esql-utils/src/utils/esql_fields_utils.test.ts +++ b/packages/kbn-esql-utils/src/utils/esql_fields_utils.test.ts @@ -7,7 +7,12 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ import type { DatatableColumn } from '@kbn/expressions-plugin/common'; -import { isESQLColumnSortable, isESQLColumnGroupable } from './esql_fields_utils'; +import { + isESQLColumnSortable, + isESQLColumnGroupable, + isESQLFieldGroupable, +} from './esql_fields_utils'; +import type { FieldSpec } from '@kbn/data-views-plugin/common'; describe('esql fields helpers', () => { describe('isESQLColumnSortable', () => { @@ -104,4 +109,46 @@ describe('esql fields helpers', () => { expect(isESQLColumnGroupable(keywordField)).toBeTruthy(); }); }); + + describe('isESQLFieldGroupable', () => { + it('returns false for unsupported fields', () => { + const fieldSpec: FieldSpec = { + name: 'unsupported', + type: 'unknown', + esTypes: ['unknown'], + searchable: true, + aggregatable: false, + isNull: false, + }; + + expect(isESQLFieldGroupable(fieldSpec)).toBeFalsy(); + }); + + it('returns false for counter fields', () => { + const fieldSpec: FieldSpec = { + name: 'tsbd_counter', + type: 'number', + esTypes: ['long'], + timeSeriesMetric: 'counter', + searchable: true, + aggregatable: false, + isNull: false, + }; + + expect(isESQLFieldGroupable(fieldSpec)).toBeFalsy(); + }); + + it('returns true for everything else', () => { + const fieldSpec: FieldSpec = { + name: 'sortable', + type: 'string', + esTypes: ['keyword'], + searchable: true, + aggregatable: false, + isNull: false, + }; + + expect(isESQLFieldGroupable(fieldSpec)).toBeTruthy(); + }); + }); }); diff --git a/packages/kbn-esql-utils/src/utils/esql_fields_utils.ts b/packages/kbn-esql-utils/src/utils/esql_fields_utils.ts index e2c5c785f8f5..fa0ae534197f 100644 --- a/packages/kbn-esql-utils/src/utils/esql_fields_utils.ts +++ b/packages/kbn-esql-utils/src/utils/esql_fields_utils.ts @@ -7,6 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import type { FieldSpec } from '@kbn/data-views-plugin/common'; import type { DatatableColumn } from '@kbn/expressions-plugin/common'; const SPATIAL_FIELDS = ['geo_point', 'geo_shape', 'point', 'shape']; @@ -40,22 +41,30 @@ export const isESQLColumnSortable = (column: DatatableColumn): boolean => { return true; }; +// Helper function to check if a field is groupable based on its type and esType +const isGroupable = (type: string | undefined, esType: string | undefined): boolean => { + // we don't allow grouping on the unknown field types + if (type === UNKNOWN_FIELD) { + return false; + } + // we don't allow grouping on tsdb counter fields + if (esType && esType.indexOf(TSDB_COUNTER_FIELDS_PREFIX) !== -1) { + return false; + } + return true; +}; + /** * Check if a column is groupable (| STATS ... BY ). * * @param column The DatatableColumn of the field. * @returns True if the column is groupable, false otherwise. */ - export const isESQLColumnGroupable = (column: DatatableColumn): boolean => { - // we don't allow grouping on the unknown field types - if (column.meta?.type === UNKNOWN_FIELD) { - return false; - } - // we don't allow grouping on tsdb counter fields - if (column.meta?.esType && column.meta?.esType?.indexOf(TSDB_COUNTER_FIELDS_PREFIX) !== -1) { - return false; - } + return isGroupable(column.meta?.type, column.meta?.esType); +}; - return true; +export const isESQLFieldGroupable = (field: FieldSpec): boolean => { + if (field.timeSeriesMetric === 'counter') return false; + return isGroupable(field.type, field.esTypes?.[0]); }; diff --git a/packages/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts b/packages/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts index fe2a85456aa1..4f649b44e44b 100644 --- a/packages/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts +++ b/packages/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts @@ -255,6 +255,7 @@ function getFunctionDefinition(ESFunctionDefinition: Record): Funct description: ESFunctionDefinition.description, alias: aliasTable[ESFunctionDefinition.name], ignoreAsSuggestion: ESFunctionDefinition.snapshot_only, + preview: ESFunctionDefinition.preview, signatures: _.uniqBy( ESFunctionDefinition.signatures.map((signature: any) => ({ ...signature, @@ -334,6 +335,7 @@ function printGeneratedFunctionsFile( description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.${name}', { defaultMessage: ${JSON.stringify( removeAsciiDocInternalCrossReferences(removeInlineAsciiDocLinks(description), functionNames) )} }),${functionDefinition.ignoreAsSuggestion ? 'ignoreAsSuggestion: true,\n' : ''} + preview: ${functionDefinition.preview || 'false'}, alias: ${alias ? `['${alias.join("', '")}']` : 'undefined'}, signatures: ${JSON.stringify(signatures, null, 2)}, supportedCommands: ${JSON.stringify(functionDefinition.supportedCommands)}, @@ -393,6 +395,9 @@ import { isLiteralItem } from '../../shared/helpers';` (async function main() { const pathToElasticsearch = process.argv[2]; + if (!pathToElasticsearch) { + throw new Error('Path to Elasticsearch is required'); + } const ESFunctionDefinitionsDirectory = join( pathToElasticsearch, diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts new file mode 100644 index 000000000000..3345f7646e2f --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts @@ -0,0 +1,334 @@ +/* + * Copyright 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 { ESQL_COMMON_NUMERIC_TYPES } from '../../shared/esql_types'; +import { pipeCompleteItem } from '../complete_items'; +import { getDateLiterals } from '../factories'; +import { log10ParameterTypes, powParameterTypes } from './constants'; +import { + attachTriggerCommand, + fields, + getFieldNamesByType, + getFunctionSignaturesByReturnType, + setup, +} from './helpers'; + +describe('WHERE ', () => { + const allEvalFns = getFunctionSignaturesByReturnType('where', 'any', { + scalar: true, + }); + test('beginning an expression', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | where /', [ + ...getFieldNamesByType('any') + .map((field) => `${field} `) + .map(attachTriggerCommand), + ...allEvalFns, + ]); + await assertSuggestions( + 'from a | eval var0 = 1 | where /', + [ + ...getFieldNamesByType('any') + .map((name) => `${name} `) + .map(attachTriggerCommand), + attachTriggerCommand('var0 '), + ...allEvalFns, + ], + { + callbacks: { + getColumnsFor: () => Promise.resolve([...fields, { name: 'var0', type: 'integer' }]), + }, + } + ); + }); + + describe('within the expression', () => { + test('after a field name', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | where keywordField /', [ + // all functions compatible with a keywordField type + ...getFunctionSignaturesByReturnType( + 'where', + 'boolean', + { + builtin: true, + }, + undefined, + ['and', 'or', 'not'] + ), + ]); + }); + + test('suggests dates after a comparison with a date', async () => { + const { assertSuggestions } = await setup(); + + const expectedComparisonWithDateSuggestions = [ + ...getDateLiterals(), + ...getFieldNamesByType(['date']), + // all functions compatible with a keywordField type + ...getFunctionSignaturesByReturnType('where', ['date'], { scalar: true }), + ]; + await assertSuggestions( + 'from a | where dateField == /', + expectedComparisonWithDateSuggestions + ); + + await assertSuggestions( + 'from a | where dateField < /', + expectedComparisonWithDateSuggestions + ); + + await assertSuggestions( + 'from a | where dateField >= /', + expectedComparisonWithDateSuggestions + ); + }); + + test('after a comparison with a string field', async () => { + const { assertSuggestions } = await setup(); + + const expectedComparisonWithTextFieldSuggestions = [ + ...getFieldNamesByType(['text', 'keyword', 'ip', 'version']), + ...getFunctionSignaturesByReturnType('where', ['text', 'keyword', 'ip', 'version'], { + scalar: true, + }), + ]; + + await assertSuggestions( + 'from a | where textField >= /', + expectedComparisonWithTextFieldSuggestions + ); + await assertSuggestions( + 'from a | where textField >= textField/', + expectedComparisonWithTextFieldSuggestions + ); + }); + + test('after a logical operator', async () => { + const { assertSuggestions } = await setup(); + + for (const op of ['and', 'or']) { + await assertSuggestions(`from a | where keywordField >= keywordField ${op} /`, [ + ...getFieldNamesByType('any'), + ...getFunctionSignaturesByReturnType('where', 'any', { scalar: true }), + ]); + await assertSuggestions(`from a | where keywordField >= keywordField ${op} doubleField /`, [ + ...getFunctionSignaturesByReturnType('where', 'boolean', { builtin: true }, ['double']), + ]); + await assertSuggestions( + `from a | where keywordField >= keywordField ${op} doubleField == /`, + [ + ...getFieldNamesByType(ESQL_COMMON_NUMERIC_TYPES), + ...getFunctionSignaturesByReturnType('where', ESQL_COMMON_NUMERIC_TYPES, { + scalar: true, + }), + ] + ); + } + }); + + test('suggests operators after a field name', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | stats a=avg(doubleField) | where a /', [ + ...getFunctionSignaturesByReturnType('where', 'any', { builtin: true, skipAssign: true }, [ + 'double', + ]), + ]); + }); + + test('accounts for fields lost in previous commands', async () => { + const { assertSuggestions } = await setup(); + + // Mind this test: suggestion is aware of previous commands when checking for fields + // in this case the doubleField has been wiped by the STATS command and suggest cannot find it's type + await assertSuggestions('from a | stats a=avg(doubleField) | where doubleField /', [], { + callbacks: { getColumnsFor: () => Promise.resolve([{ name: 'a', type: 'double' }]) }, + }); + }); + + test('suggests function arguments', async () => { + const { assertSuggestions } = await setup(); + + // The editor automatically inject the final bracket, so it is not useful to test with just open bracket + await assertSuggestions( + 'from a | where log10(/)', + [ + ...getFieldNamesByType(log10ParameterTypes), + ...getFunctionSignaturesByReturnType( + 'where', + log10ParameterTypes, + { scalar: true }, + undefined, + ['log10'] + ), + ], + { triggerCharacter: '(' } + ); + await assertSuggestions( + 'from a | WHERE pow(doubleField, /)', + [ + ...getFieldNamesByType(powParameterTypes), + ...getFunctionSignaturesByReturnType( + 'where', + powParameterTypes, + { scalar: true }, + undefined, + ['pow'] + ), + ], + { triggerCharacter: ',' } + ); + }); + + test('suggests boolean and numeric operators after a numeric function result', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from a | where log10(doubleField) /', [ + ...getFunctionSignaturesByReturnType('where', 'double', { builtin: true }, ['double']), + ...getFunctionSignaturesByReturnType('where', 'boolean', { builtin: true }, ['double']), + ]); + }); + + test('suggestions after NOT', async () => { + const { assertSuggestions } = await setup(); + await assertSuggestions('from index | WHERE keywordField not /', [ + 'LIKE $0', + 'RLIKE $0', + 'IN $0', + ]); + await assertSuggestions('from index | WHERE keywordField NOT /', [ + 'LIKE $0', + 'RLIKE $0', + 'IN $0', + ]); + await assertSuggestions('from index | WHERE not /', [ + ...getFieldNamesByType('boolean').map((name) => attachTriggerCommand(`${name} `)), + ...getFunctionSignaturesByReturnType('where', 'boolean', { scalar: true }), + ]); + await assertSuggestions('FROM index | WHERE NOT ENDS_WITH(keywordField, "foo") /', [ + ...getFunctionSignaturesByReturnType('where', 'boolean', { builtin: true }, ['boolean']), + pipeCompleteItem, + ]); + await assertSuggestions('from index | WHERE keywordField IS NOT/', [ + '!= $0', + '== $0', + 'AND $0', + 'IN $0', + 'IS NOT NULL', + 'IS NULL', + 'NOT', + 'OR $0', + '| ', + ]); + + await assertSuggestions('from index | WHERE keywordField IS NOT /', [ + '!= $0', + '== $0', + 'AND $0', + 'IN $0', + 'IS NOT NULL', + 'IS NULL', + 'NOT', + 'OR $0', + '| ', + ]); + }); + + test('suggestions after IN', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('from index | WHERE doubleField in /', ['( $0 )']); + await assertSuggestions('from index | WHERE doubleField not in /', ['( $0 )']); + await assertSuggestions( + 'from index | WHERE doubleField not in (/)', + [ + ...getFieldNamesByType('double').filter((name) => name !== 'doubleField'), + ...getFunctionSignaturesByReturnType('where', 'double', { scalar: true }), + ], + { triggerCharacter: '(' } + ); + await assertSuggestions('from index | WHERE doubleField in ( `any#Char$Field`, /)', [ + ...getFieldNamesByType('double').filter( + (name) => name !== '`any#Char$Field`' && name !== 'doubleField' + ), + ...getFunctionSignaturesByReturnType('where', 'double', { scalar: true }), + ]); + await assertSuggestions('from index | WHERE doubleField not in ( `any#Char$Field`, /)', [ + ...getFieldNamesByType('double').filter( + (name) => name !== '`any#Char$Field`' && name !== 'doubleField' + ), + ...getFunctionSignaturesByReturnType('where', 'double', { scalar: true }), + ]); + }); + + test('suggestions after IS (NOT) NULL', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('FROM index | WHERE tags.keyword IS NULL /', [ + 'AND $0', + 'OR $0', + '| ', + ]); + + await assertSuggestions('FROM index | WHERE tags.keyword IS NOT NULL /', [ + 'AND $0', + 'OR $0', + '| ', + ]); + }); + + test('suggestions after an arithmetic expression', async () => { + const { assertSuggestions } = await setup(); + + await assertSuggestions('FROM index | WHERE doubleField + doubleField /', [ + ...getFunctionSignaturesByReturnType('where', 'any', { builtin: true, skipAssign: true }, [ + 'double', + ]), + ]); + }); + + test('pipe suggestion after complete expression', async () => { + const { suggest } = await setup(); + expect(await suggest('from index | WHERE doubleField != doubleField /')).toContainEqual( + expect.objectContaining({ + label: '|', + }) + ); + }); + + test('attaches ranges', async () => { + const { suggest } = await setup(); + + const suggestions = await suggest('FROM index | WHERE doubleField IS N/'); + + expect(suggestions).toContainEqual( + expect.objectContaining({ + text: 'IS NOT NULL', + rangeToReplace: { + start: 32, + end: 36, + }, + }) + ); + + expect(suggestions).toContainEqual( + expect.objectContaining({ + text: 'IS NULL', + rangeToReplace: { + start: 32, + end: 36, + }, + }) + ); + }); + }); +}); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.eval.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.eval.test.ts index 81fd8f7f4390..5c67bfedbae7 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.eval.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.eval.test.ts @@ -535,17 +535,6 @@ describe('autocomplete.suggest', () => { { triggerCharacter: ' ' } ); await assertSuggestions('from a | eval a = 1 year /', [',', '| ', 'IS NOT NULL', 'IS NULL']); - await assertSuggestions('from a | eval a = 1 day + 2 /', [',', '| ']); - await assertSuggestions( - 'from a | eval 1 day + 2 /', - [ - ...dateSuggestions, - ...getFunctionSignaturesByReturnType('eval', 'any', { builtin: true, skipAssign: true }, [ - 'integer', - ]), - ], - { triggerCharacter: ' ' } - ); await assertSuggestions( 'from a | eval var0=date_trunc(/)', [ diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/hidden_functions_and_commands.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/hidden_functions_and_commands.test.ts index cc4562f999fe..02cc79c32679 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/hidden_functions_and_commands.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/hidden_functions_and_commands.test.ts @@ -50,6 +50,7 @@ describe('hidden functions', () => { expect(suggestedFunctions).toContain('VISIBLE_FUNCTION($0)'); expect(suggestedFunctions).not.toContain('HIDDEN_FUNCTION($0)'); }); + it('does not suggest hidden agg functions', async () => { setTestFunctions([ { diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts index 9e7fa4566d75..5f3a2e45f9e1 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts @@ -11,12 +11,7 @@ import { suggest } from './autocomplete'; import { scalarFunctionDefinitions } from '../definitions/generated/scalar_functions'; import { timeUnitsToSuggest } from '../definitions/literals'; import { commandDefinitions as unmodifiedCommandDefinitions } from '../definitions/commands'; -import { - getDateLiterals, - getSafeInsertText, - TIME_SYSTEM_PARAMS, - TRIGGER_SUGGESTION_COMMAND, -} from './factories'; +import { getSafeInsertText, TIME_SYSTEM_PARAMS, TRIGGER_SUGGESTION_COMMAND } from './factories'; import { camelCase } from 'lodash'; import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; import { @@ -34,8 +29,7 @@ import { fields, } from './__tests__/helpers'; import { METADATA_FIELDS } from '../shared/constants'; -import { ESQL_COMMON_NUMERIC_TYPES, ESQL_STRING_TYPES } from '../shared/esql_types'; -import { log10ParameterTypes, powParameterTypes } from './__tests__/constants'; +import { ESQL_STRING_TYPES } from '../shared/esql_types'; import { getRecommendedQueries } from './recommended_queries/templates'; import { getDateHistogramCompletionItem } from './commands/stats/util'; @@ -130,149 +124,6 @@ describe('autocomplete', () => { } }); - describe('where', () => { - const allEvalFns = getFunctionSignaturesByReturnType('where', 'any', { - scalar: true, - }); - testSuggestions('from a | where /', [ - ...getFieldNamesByType('any').map((field) => `${field} `), - ...allEvalFns, - ]); - testSuggestions('from a | eval var0 = 1 | where /', [ - ...getFieldNamesByType('any').map((name) => `${name} `), - 'var0', - ...allEvalFns, - ]); - testSuggestions('from a | where keywordField /', [ - // all functions compatible with a keywordField type - ...getFunctionSignaturesByReturnType( - 'where', - 'boolean', - { - builtin: true, - }, - undefined, - ['and', 'or', 'not'] - ), - ]); - - const expectedComparisonWithDateSuggestions = [ - ...getDateLiterals(), - ...getFieldNamesByType(['date']), - // all functions compatible with a keywordField type - ...getFunctionSignaturesByReturnType('where', ['date'], { scalar: true }), - ]; - testSuggestions('from a | where dateField == /', expectedComparisonWithDateSuggestions); - - testSuggestions('from a | where dateField < /', expectedComparisonWithDateSuggestions); - - testSuggestions('from a | where dateField >= /', expectedComparisonWithDateSuggestions); - - const expectedComparisonWithTextFieldSuggestions = [ - ...getFieldNamesByType(['text', 'keyword', 'ip', 'version']), - ...getFunctionSignaturesByReturnType('where', ['text', 'keyword', 'ip', 'version'], { - scalar: true, - }), - ]; - testSuggestions('from a | where textField >= /', expectedComparisonWithTextFieldSuggestions); - testSuggestions( - 'from a | where textField >= textField/', - expectedComparisonWithTextFieldSuggestions - ); - for (const op of ['and', 'or']) { - testSuggestions(`from a | where keywordField >= keywordField ${op} /`, [ - ...getFieldNamesByType('any'), - ...getFunctionSignaturesByReturnType('where', 'any', { scalar: true }), - ]); - testSuggestions(`from a | where keywordField >= keywordField ${op} doubleField /`, [ - ...getFunctionSignaturesByReturnType('where', 'boolean', { builtin: true }, ['double']), - ]); - testSuggestions(`from a | where keywordField >= keywordField ${op} doubleField == /`, [ - ...getFieldNamesByType(ESQL_COMMON_NUMERIC_TYPES), - ...getFunctionSignaturesByReturnType('where', ESQL_COMMON_NUMERIC_TYPES, { - scalar: true, - }), - ]); - } - testSuggestions('from a | stats a=avg(doubleField) | where a /', [ - ...getFunctionSignaturesByReturnType('where', 'any', { builtin: true, skipAssign: true }, [ - 'double', - ]), - ]); - // Mind this test: suggestion is aware of previous commands when checking for fields - // in this case the doubleField has been wiped by the STATS command and suggest cannot find it's type - // @TODO: verify this is the correct behaviour in this case or if we want a "generic" suggestion anyway - testSuggestions( - 'from a | stats a=avg(doubleField) | where doubleField /', - [], - undefined, - // make the fields suggest aware of the previous STATS, leave the other callbacks untouched - [[{ name: 'a', type: 'double' }], undefined, undefined] - ); - // The editor automatically inject the final bracket, so it is not useful to test with just open bracket - testSuggestions( - 'from a | where log10(/)', - [ - ...getFieldNamesByType(log10ParameterTypes), - ...getFunctionSignaturesByReturnType( - 'where', - log10ParameterTypes, - { scalar: true }, - undefined, - ['log10'] - ), - ], - '(' - ); - testSuggestions('from a | where log10(doubleField) /', [ - ...getFunctionSignaturesByReturnType('where', 'double', { builtin: true }, ['double']), - ...getFunctionSignaturesByReturnType('where', 'boolean', { builtin: true }, ['double']), - ]); - testSuggestions( - 'from a | WHERE pow(doubleField, /)', - [ - ...getFieldNamesByType(powParameterTypes), - ...getFunctionSignaturesByReturnType( - 'where', - powParameterTypes, - { scalar: true }, - undefined, - ['pow'] - ), - ], - ',' - ); - - testSuggestions('from index | WHERE keywordField not /', ['LIKE $0', 'RLIKE $0', 'IN $0']); - testSuggestions('from index | WHERE keywordField NOT /', ['LIKE $0', 'RLIKE $0', 'IN $0']); - testSuggestions('from index | WHERE not /', [ - ...getFieldNamesByType('boolean'), - ...getFunctionSignaturesByReturnType('eval', 'boolean', { scalar: true }), - ]); - testSuggestions('from index | WHERE doubleField in /', ['( $0 )']); - testSuggestions('from index | WHERE doubleField not in /', ['( $0 )']); - testSuggestions( - 'from index | WHERE doubleField not in (/)', - [ - ...getFieldNamesByType('double').filter((name) => name !== 'doubleField'), - ...getFunctionSignaturesByReturnType('where', 'double', { scalar: true }), - ], - '(' - ); - testSuggestions('from index | WHERE doubleField in ( `any#Char$Field`, /)', [ - ...getFieldNamesByType('double').filter( - (name) => name !== '`any#Char$Field`' && name !== 'doubleField' - ), - ...getFunctionSignaturesByReturnType('where', 'double', { scalar: true }), - ]); - testSuggestions('from index | WHERE doubleField not in ( `any#Char$Field`, /)', [ - ...getFieldNamesByType('double').filter( - (name) => name !== '`any#Char$Field`' && name !== 'doubleField' - ), - ...getFunctionSignaturesByReturnType('where', 'double', { scalar: true }), - ]); - }); - describe('grok', () => { const constantPattern = '"%{WORD:firstWord}"'; const subExpressions = [ @@ -766,6 +617,21 @@ describe('autocomplete', () => { ['and', 'or', 'not'] ) ); + + // WHERE function + testSuggestions( + 'FROM index1 | WHERE ABS(integerField) i/', + getFunctionSignaturesByReturnType( + 'where', + 'any', + { + builtin: true, + skipAssign: true, + }, + ['integer'], + ['and', 'or', 'not'] + ) + ); }); describe('advancing the cursor and opening the suggestion menu automatically ✨', () => { @@ -1295,27 +1161,35 @@ describe('autocomplete', () => { describe('Replacement ranges are attached when needed', () => { testSuggestions('FROM a | WHERE doubleField IS NOT N/', [ - { text: 'IS NOT NULL', rangeToReplace: { start: 28, end: 35 } }, - { text: 'IS NULL', rangeToReplace: { start: 36, end: 36 } }, + { text: 'IS NOT NULL', rangeToReplace: { start: 28, end: 36 } }, + { text: 'IS NULL', rangeToReplace: { start: 37, end: 37 } }, '!= $0', '== $0', 'IN $0', 'AND $0', 'NOT', 'OR $0', + // pipe doesn't make sense here, but Monaco will filter it out. + // see https://github.com/elastic/kibana/issues/199401 for an explanation + // of why this happens + '| ', ]); testSuggestions('FROM a | WHERE doubleField IS N/', [ - { text: 'IS NOT NULL', rangeToReplace: { start: 28, end: 31 } }, - { text: 'IS NULL', rangeToReplace: { start: 28, end: 31 } }, - { text: '!= $0', rangeToReplace: { start: 32, end: 32 } }, + { text: 'IS NOT NULL', rangeToReplace: { start: 28, end: 32 } }, + { text: 'IS NULL', rangeToReplace: { start: 28, end: 32 } }, + { text: '!= $0', rangeToReplace: { start: 33, end: 33 } }, '== $0', 'IN $0', 'AND $0', 'NOT', 'OR $0', + // pipe doesn't make sense here, but Monaco will filter it out. + // see https://github.com/elastic/kibana/issues/199401 for an explanation + // of why this happens + '| ', ]); testSuggestions('FROM a | EVAL doubleField IS NOT N/', [ - { text: 'IS NOT NULL', rangeToReplace: { start: 27, end: 34 } }, + { text: 'IS NOT NULL', rangeToReplace: { start: 27, end: 35 } }, 'IS NULL', '!= $0', '== $0', @@ -1324,6 +1198,7 @@ describe('autocomplete', () => { 'NOT', 'OR $0', ]); + describe('dot-separated field names', () => { testSuggestions( 'FROM a | KEEP field.nam/', diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts index ecb46682b041..bae10b4c321f 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts @@ -24,7 +24,6 @@ import { getCommandOption, getFunctionDefinition, getLastNonWhitespaceChar, - isArrayType, isAssignment, isAssignmentComplete, isColumnItem, @@ -48,6 +47,7 @@ import { sourceExists, findFinalWord, getAllCommands, + getExpressionType, } from '../shared/helpers'; import { collectVariables, excludeVariablesFromCurrentCommand } from '../shared/variables'; import type { ESQLPolicy, ESQLRealField, ESQLVariable, ReferenceMaps } from '../validation/types'; @@ -56,10 +56,7 @@ import { colonCompleteItem, commaCompleteItem, getAssignmentDefinitionCompletitionItem, - getBuiltinCompatibleFunctionDefinition, getCommandAutocompleteDefinitions, - getNextTokenForNot, - listCompleteItem, pipeCompleteItem, semiColonCompleteItem, } from './complete_items'; @@ -80,6 +77,8 @@ import { getDateLiterals, buildFieldsDefinitionsWithMetadata, TRIGGER_SUGGESTION_COMMAND, + getOperatorSuggestions, + getSuggestionsAfterNot, } from './factories'; import { EDITOR_MARKER, METADATA_FIELDS } from '../shared/constants'; import { getAstContext, removeMarkerArgFromArgsList } from '../shared/context'; @@ -92,10 +91,8 @@ import { import { ESQLCallbacks, ESQLSourceResult } from '../shared/types'; import { getFunctionsToIgnoreForStats, - getOverlapRange, getQueryForFields, getSourcesFromCommands, - getSupportedTypesForBinaryOperators, isAggFunctionUsedAlready, removeQuoteForSuggestedSources, getValidSignaturesAndTypesToSuggestNext, @@ -103,8 +100,10 @@ import { getFieldsOrFunctionsSuggestions, pushItUpInTheList, extractTypeFromASTArg, + getSuggestionsToRightOfOperatorExpression, + checkFunctionInvocationComplete, } from './helper'; -import { FunctionParameter, isParameterType, isReturnType } from '../definitions/types'; +import { FunctionParameter, isParameterType } from '../definitions/types'; import { metadataOption } from '../definitions/options'; import { comparisonFunctions } from '../definitions/builtin'; import { getRecommendedQueriesSuggestions } from './recommended_queries/suggestions'; @@ -321,16 +320,12 @@ function findNewVariable(variables: Map) { function workoutBuiltinOptions( nodeArg: ESQLAstItem, references: Pick -): { skipAssign: boolean; commandsToInclude?: string[] } { - const commandsToInclude = - (isSingleItem(nodeArg) && nodeArg.text?.toLowerCase().trim().endsWith('null')) ?? false - ? ['and', 'or'] - : undefined; - +): { ignored?: string[] } { // skip assign operator if it's a function or an existing field to avoid promoting shadowing return { - skipAssign: Boolean(!isColumnItem(nodeArg) || getColumnForASTNode(nodeArg, references)), - commandsToInclude, + ignored: Boolean(!isColumnItem(nodeArg) || getColumnForASTNode(nodeArg, references)) + ? ['='] + : undefined, }; } @@ -340,42 +335,19 @@ function areCurrentArgsValid( references: Pick ) { // unfortunately here we need to bake some command-specific logic - if (command.name === 'stats') { - if (node) { - // consider the following expressions not complete yet - // ... | stats a - // ... | stats a = - if (isColumnItem(node) || (isAssignment(node) && !isAssignmentComplete(node))) { - return false; - } - } - } if (command.name === 'eval') { if (node) { if (isFunctionItem(node)) { if (isAssignment(node)) { return isAssignmentComplete(node); } else { - return isFunctionArgComplete(node, references).complete; + return checkFunctionInvocationComplete(node, (expression) => + getExpressionType(expression, references.fields, references.variables) + ).complete; } } } } - if (command.name === 'where') { - if (node) { - if ( - isColumnItem(node) || - (isFunctionItem(node) && !isFunctionArgComplete(node, references).complete) - ) { - return false; - } else { - return ( - extractTypeFromASTArg(node, references) === - getCommandDefinition(command.name).signature.params[0].type - ); - } - } - } if (command.name === 'rename') { if (node) { if (isColumnItem(node)) { @@ -386,45 +358,6 @@ function areCurrentArgsValid( return true; } -// @TODO: refactor this to be shared with validation -function isFunctionArgComplete( - arg: ESQLFunction, - references: Pick -) { - const fnDefinition = getFunctionDefinition(arg.name); - if (!fnDefinition) { - return { complete: false }; - } - const cleanedArgs = removeMarkerArgFromArgsList(arg)!.args; - const argLengthCheck = fnDefinition.signatures.some((def) => { - if (def.minParams && cleanedArgs.length >= def.minParams) { - return true; - } - if (cleanedArgs.length === def.params.length) { - return true; - } - return cleanedArgs.length >= def.params.filter(({ optional }) => !optional).length; - }); - if (!argLengthCheck) { - return { complete: false, reason: 'fewArgs' }; - } - if (fnDefinition.name === 'in' && Array.isArray(arg.args[1]) && !arg.args[1].length) { - return { complete: false, reason: 'fewArgs' }; - } - const hasCorrectTypes = fnDefinition.signatures.some((def) => { - return arg.args.every((a, index) => { - return ( - (fnDefinition.name.endsWith('null') && def.params[index].type === 'any') || - def.params[index].type === extractTypeFromASTArg(a, references) - ); - }); - }); - if (!hasCorrectTypes) { - return { complete: false, reason: 'wrongTypes' }; - } - return { complete: true }; -} - function extractArgMeta( commandOrOption: ESQLCommand | ESQLCommandOption, node: ESQLSingleAstItem | undefined @@ -478,6 +411,8 @@ async function getSuggestionsWithinCommandExpression( getColumnsByType, (col: string) => Boolean(getColumnByName(col, references)), () => findNewVariable(anyVariables), + (expression: ESQLAstItem | undefined) => + getExpressionType(expression, references.fields, references.variables), getPreferences ); } else { @@ -629,7 +564,7 @@ async function getExpressionSuggestionsByType( // ... | ROW field NOT // ... | EVAL field NOT // there's not way to know the type of the field here, so suggest anything - suggestions.push(...getNextTokenForNot(command.name, option?.name, 'any')); + suggestions.push(...getSuggestionsAfterNot()); } else { // i.e. // ... | ROW @@ -717,13 +652,11 @@ async function getExpressionSuggestionsByType( const nodeArgType = extractTypeFromASTArg(nodeArg, references); if (isParameterType(nodeArgType)) { suggestions.push( - ...getBuiltinCompatibleFunctionDefinition( - command.name, - undefined, - nodeArgType, - undefined, - workoutBuiltinOptions(nodeArg, references) - ) + ...getOperatorSuggestions({ + command: command.name, + leftParamType: nodeArgType, + ignored: workoutBuiltinOptions(nodeArg, references).ignored, + }) ); } else { suggestions.push(getAssignmentDefinitionCompletitionItem()); @@ -754,9 +687,7 @@ async function getExpressionSuggestionsByType( )) ); if (['show', 'meta'].includes(command.name)) { - suggestions.push( - ...getBuiltinCompatibleFunctionDefinition(command.name, undefined, 'any') - ); + suggestions.push(...getOperatorSuggestions({ command: command.name })); } } } @@ -770,13 +701,11 @@ async function getExpressionSuggestionsByType( const [rightArg] = nodeArg.args[1] as [ESQLSingleAstItem]; const nodeArgType = extractTypeFromASTArg(rightArg, references); suggestions.push( - ...getBuiltinCompatibleFunctionDefinition( - command.name, - undefined, - isParameterType(nodeArgType) ? nodeArgType : 'any', - undefined, - workoutBuiltinOptions(rightArg, references) - ) + ...getOperatorSuggestions({ + command: command.name, + leftParamType: isParameterType(nodeArgType) ? nodeArgType : 'any', + ignored: workoutBuiltinOptions(nodeArg, references).ignored, + }) ); if (isNumericType(nodeArgType) && isLiteralItem(rightArg)) { // ... EVAL var = 1 @@ -808,18 +737,16 @@ async function getExpressionSuggestionsByType( )) ); } else { - const nodeArgType = extractTypeFromASTArg(nodeArg, references); suggestions.push( - ...(await getBuiltinFunctionNextArgument( - innerText, - command, - option, - argDef, - nodeArg, - (nodeArgType as string) || 'any', - references, - getFieldsByType - )) + ...(await getSuggestionsToRightOfOperatorExpression({ + queryText: innerText, + commandName: command.name, + optionName: option?.name, + rootOperator: nodeArg, + getExpressionType: (expression) => + getExpressionType(expression, references.fields, references.variables), + getColumnsByType: getFieldsByType, + })) ); if (nodeArg.args.some(isTimeIntervalItem)) { const lastFnArg = nodeArg.args[nodeArg.args.length - 1]; @@ -859,7 +786,7 @@ async function getExpressionSuggestionsByType( // i.e. // ... | WHERE field NOT // there's not way to know the type of the field here, so suggest anything - suggestions.push(...getNextTokenForNot(command.name, option?.name, 'any')); + suggestions.push(...getSuggestionsAfterNot()); } else { // ... | // In this case start suggesting something not strictly based on type @@ -906,28 +833,25 @@ async function getExpressionSuggestionsByType( ); } else { suggestions.push( - ...(await getBuiltinFunctionNextArgument( - innerText, - command, - option, - argDef, - nodeArg, - nodeArgType as string, - references, - getFieldsByType - )) + ...(await getSuggestionsToRightOfOperatorExpression({ + queryText: innerText, + commandName: command.name, + optionName: option?.name, + rootOperator: nodeArg, + getExpressionType: (expression) => + getExpressionType(expression, references.fields, references.variables), + getColumnsByType: getFieldsByType, + })) ); } } else if (isParameterType(nodeArgType)) { // i.e. ... | field suggestions.push( - ...getBuiltinCompatibleFunctionDefinition( - command.name, - undefined, - nodeArgType, - undefined, - workoutBuiltinOptions(nodeArg, references) - ) + ...getOperatorSuggestions({ + command: command.name, + leftParamType: nodeArgType, + ignored: workoutBuiltinOptions(nodeArg, references).ignored, + }) ); } } @@ -1080,110 +1004,6 @@ async function getExpressionSuggestionsByType( return uniqBy(suggestions, (suggestion) => suggestion.text); } -async function getBuiltinFunctionNextArgument( - queryText: string, - command: ESQLCommand, - option: ESQLCommandOption | undefined, - argDef: { type: string }, - nodeArg: ESQLFunction, - nodeArgType: string, - references: Pick, - getFieldsByType: GetColumnsByTypeFn -) { - const suggestions = []; - const isFnComplete = isFunctionArgComplete(nodeArg, references); - - if (isFnComplete.complete) { - // i.e. ... | field > 0 - // i.e. ... | field + otherN - suggestions.push( - ...getBuiltinCompatibleFunctionDefinition( - command.name, - option?.name, - isParameterType(nodeArgType) ? nodeArgType : 'any', - undefined, - workoutBuiltinOptions(nodeArg, references) - ) - ); - } else { - // i.e. ... | field >= - // i.e. ... | field + - // i.e. ... | field and - - // Because it's an incomplete function, need to extract the type of the current argument - // and suggest the next argument based on types - - // pick the last arg and check its type to verify whether is incomplete for the given function - const cleanedArgs = removeMarkerArgFromArgsList(nodeArg)!.args; - const nestedType = extractTypeFromASTArg(nodeArg.args[cleanedArgs.length - 1], references); - - if (isFnComplete.reason === 'fewArgs') { - const fnDef = getFunctionDefinition(nodeArg.name); - if ( - fnDef?.signatures.every(({ params }) => - params.some(({ type }) => isArrayType(type as string)) - ) - ) { - suggestions.push(listCompleteItem); - } else { - const finalType = nestedType || nodeArgType || 'any'; - const supportedTypes = getSupportedTypesForBinaryOperators(fnDef, finalType as string); - - suggestions.push( - ...(await getFieldsOrFunctionsSuggestions( - // this is a special case with AND/OR - // expression AND/OR - // technically another boolean value should be suggested, but it is a better experience - // to actually suggest a wider set of fields/functions - finalType === 'boolean' && getFunctionDefinition(nodeArg.name)?.type === 'builtin' - ? ['any'] - : (supportedTypes as string[]), - command.name, - option?.name, - getFieldsByType, - { - functions: true, - fields: true, - variables: references.variables, - } - )) - ); - } - } - if (isFnComplete.reason === 'wrongTypes') { - if (nestedType) { - // suggest something to complete the builtin function - if ( - nestedType !== argDef.type && - isParameterType(nestedType) && - isReturnType(argDef.type) - ) { - suggestions.push( - ...getBuiltinCompatibleFunctionDefinition( - command.name, - undefined, - nestedType, - [argDef.type], - workoutBuiltinOptions(nodeArg, references) - ) - ); - } - } - } - } - return suggestions.map((s) => { - const overlap = getOverlapRange(queryText, s.text); - const offset = overlap.start === overlap.end ? 1 : 0; - return { - ...s, - rangeToReplace: { - start: overlap.start + offset, - end: overlap.end + offset, - }, - }; - }); -} - const addCommaIf = (condition: boolean, text: string) => (condition ? `${text},` : text); async function getFunctionArgsSuggestions( @@ -1615,10 +1435,7 @@ async function getOptionArgsSuggestions( // ... | ENRICH ... WITH a // effectively only assign will apper suggestions.push( - ...pushItUpInTheList( - getBuiltinCompatibleFunctionDefinition(command.name, undefined, 'any'), - true - ) + ...pushItUpInTheList(getOperatorSuggestions({ command: command.name }), true) ); } diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/stats/index.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/stats/index.ts index 46a37d36eacc..ac70ac1a1a5c 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/stats/index.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/stats/index.ts @@ -7,7 +7,8 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { ESQLCommand } from '@kbn/esql-ast'; +import type { ESQLAstItem, ESQLCommand } from '@kbn/esql-ast'; +import { SupportedDataType } from '../../../definitions/types'; import type { GetColumnsByTypeFn, SuggestionRawDefinition } from '../../types'; import { TRIGGER_SUGGESTION_COMMAND, @@ -24,6 +25,7 @@ export async function suggest( getColumnsByType: GetColumnsByTypeFn, _columnExists: (column: string) => boolean, getSuggestedVariableName: () => string, + _getExpressionType: (expression: ESQLAstItem | undefined) => SupportedDataType | 'unknown', getPreferences?: () => Promise<{ histogramBarTarget: number } | undefined> ): Promise { const pos = getPosition(innerText, command); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/stats/util.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/stats/util.ts index c9abaa5c5408..0730b004e28d 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/stats/util.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/stats/util.ts @@ -99,6 +99,6 @@ export const getDateHistogramCompletionItem: ( defaultMessage: 'Add date histogram using bucket()', } ), - sortText: '1A', + sortText: '1', command: TRIGGER_SUGGESTION_COMMAND, }); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/index.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/index.ts new file mode 100644 index 000000000000..dc2ab341e961 --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/index.ts @@ -0,0 +1,183 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 { + Walker, + type ESQLAstItem, + type ESQLCommand, + type ESQLSingleAstItem, + type ESQLFunction, +} from '@kbn/esql-ast'; +import { logicalOperators } from '../../../definitions/builtin'; +import { isParameterType, type SupportedDataType } from '../../../definitions/types'; +import { isFunctionItem } from '../../../shared/helpers'; +import type { GetColumnsByTypeFn, SuggestionRawDefinition } from '../../types'; +import { + getFunctionSuggestions, + getOperatorSuggestion, + getOperatorSuggestions, + getSuggestionsAfterNot, +} from '../../factories'; +import { getOverlapRange, getSuggestionsToRightOfOperatorExpression } from '../../helper'; +import { getPosition } from './util'; +import { pipeCompleteItem } from '../../complete_items'; + +export async function suggest( + innerText: string, + command: ESQLCommand<'where'>, + getColumnsByType: GetColumnsByTypeFn, + _columnExists: (column: string) => boolean, + _getSuggestedVariableName: () => string, + getExpressionType: (expression: ESQLAstItem | undefined) => SupportedDataType | 'unknown', + _getPreferences?: () => Promise<{ histogramBarTarget: number } | undefined> +): Promise { + const suggestions: SuggestionRawDefinition[] = []; + + /** + * The logic for WHERE suggestions is basically the logic for expression suggestions. + * I assume we will eventually extract much of this to be a shared function among WHERE and EVAL + * and anywhere else the user can enter a generic expression. + */ + const expressionRoot = command.args[0] as ESQLSingleAstItem | undefined; + + switch (getPosition(innerText, command)) { + /** + * After a column name + */ + case 'after_column': + const columnType = getExpressionType(expressionRoot); + + if (!isParameterType(columnType)) { + break; + } + + suggestions.push( + ...getOperatorSuggestions({ + command: 'where', + leftParamType: columnType, + // no assignments allowed in WHERE + ignored: ['='], + }) + ); + break; + + /** + * After a complete (non-operator) function call + */ + case 'after_function': + const returnType = getExpressionType(expressionRoot); + + if (!isParameterType(returnType)) { + break; + } + + suggestions.push( + ...getOperatorSuggestions({ + command: 'where', + leftParamType: returnType, + ignored: ['='], + }) + ); + + break; + + /** + * After a NOT keyword + * + * the NOT function is a special operator that can be used in different ways, + * and not all these are mapped within the AST data structure: in particular + * NOT + * is an incomplete statement and it results in a missing AST node, so we need to detect + * from the query string itself + * + * (this comment was copied but seems to still apply) + */ + case 'after_not': + if (expressionRoot && isFunctionItem(expressionRoot) && expressionRoot.name === 'not') { + suggestions.push( + ...getFunctionSuggestions({ command: 'where', returnTypes: ['boolean'] }), + ...(await getColumnsByType('boolean', [], { advanceCursor: true, openSuggestions: true })) + ); + } else { + suggestions.push(...getSuggestionsAfterNot()); + } + + break; + + /** + * After an operator (e.g. AND, OR, IS NULL, +, etc.) + */ + case 'after_operator': + if (!expressionRoot) { + break; + } + + if (!isFunctionItem(expressionRoot) || expressionRoot.subtype === 'variadic-call') { + // this is already guaranteed in the getPosition function, but TypeScript doesn't know + break; + } + + let rightmostOperator = expressionRoot; + // get rightmost function + const walker = new Walker({ + visitFunction: (fn: ESQLFunction) => { + if (fn.location.min > rightmostOperator.location.min && fn.subtype !== 'variadic-call') + rightmostOperator = fn; + }, + }); + walker.walkFunction(expressionRoot); + + // See https://github.com/elastic/kibana/issues/199401 for an explanation of + // why this check has to be so convoluted + if (rightmostOperator.text.toLowerCase().trim().endsWith('null')) { + suggestions.push(...logicalOperators.map(getOperatorSuggestion)); + break; + } + + suggestions.push( + ...(await getSuggestionsToRightOfOperatorExpression({ + queryText: innerText, + commandName: 'where', + rootOperator: rightmostOperator, + preferredExpressionType: 'boolean', + getExpressionType, + getColumnsByType, + })) + ); + + break; + + case 'empty_expression': + const columnSuggestions = await getColumnsByType('any', [], { + advanceCursor: true, + openSuggestions: true, + }); + suggestions.push(...columnSuggestions, ...getFunctionSuggestions({ command: 'where' })); + + break; + } + + // Is this a complete expression of the right type? + // If so, we can call it done and suggest a pipe + if (getExpressionType(expressionRoot) === 'boolean') { + suggestions.push(pipeCompleteItem); + } + + return suggestions.map((s) => { + const overlap = getOverlapRange(innerText, s.text); + const offset = overlap.start === overlap.end ? 1 : 0; + return { + ...s, + rangeToReplace: { + start: overlap.start + offset, + end: overlap.end + offset, + }, + }; + }); +} diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/util.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/util.ts new file mode 100644 index 000000000000..c969e7e37461 --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/util.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", 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 { ESQLCommand, ESQLSingleAstItem } from '@kbn/esql-ast'; +import { isColumnItem, isFunctionItem } from '../../../shared/helpers'; + +export type CaretPosition = + | 'after_column' + | 'after_function' + | 'after_not' + | 'after_operator' + | 'empty_expression'; + +export const getPosition = (innerText: string, command: ESQLCommand): CaretPosition => { + const expressionRoot = command.args[0] as ESQLSingleAstItem | undefined; + + const endsWithNot = / not$/i.test(innerText.trimEnd()); + if ( + endsWithNot && + !( + expressionRoot && + isFunctionItem(expressionRoot) && + // See https://github.com/elastic/kibana/issues/199401 + // for more information on this check... + ['is null', 'is not null'].includes(expressionRoot.name) + ) + ) { + return 'after_not'; + } + + if (expressionRoot) { + if (isColumnItem(expressionRoot)) { + return 'after_column'; + } + + if (isFunctionItem(expressionRoot) && expressionRoot.subtype === 'variadic-call') { + return 'after_function'; + } + + if (isFunctionItem(expressionRoot) && expressionRoot.subtype !== 'variadic-call') { + return 'after_operator'; + } + } + + return 'empty_expression'; +}; diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts index b115e30c47ef..0c448d4814f9 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts @@ -11,81 +11,17 @@ import { i18n } from '@kbn/i18n'; import type { ItemKind, SuggestionRawDefinition } from './types'; import { builtinFunctions } from '../definitions/builtin'; import { - getSuggestionBuiltinDefinition, + getOperatorSuggestion, getSuggestionCommandDefinition, TRIGGER_SUGGESTION_COMMAND, - buildConstantsDefinitions, } from './factories'; -import { CommandDefinition, FunctionParameterType, FunctionReturnType } from '../definitions/types'; -import { getTestFunctions } from '../shared/test_functions'; +import { CommandDefinition } from '../definitions/types'; export function getAssignmentDefinitionCompletitionItem() { const assignFn = builtinFunctions.find(({ name }) => name === '=')!; - return getSuggestionBuiltinDefinition(assignFn); + return getOperatorSuggestion(assignFn); } -export const getNextTokenForNot = ( - command: string, - option: string | undefined, - argType: string -): SuggestionRawDefinition[] => { - const compatibleFunctions = builtinFunctions.filter( - ({ name, supportedCommands, supportedOptions, ignoreAsSuggestion }) => - !ignoreAsSuggestion && - !/not_/.test(name) && - (option ? supportedOptions?.includes(option) : supportedCommands.includes(command)) - ); - if (argType === 'string' || argType === 'any') { - // suggest IS, LIKE, RLIKE and TRUE/FALSE - return compatibleFunctions - .filter(({ name }) => name === 'like' || name === 'rlike' || name === 'in') - .map(getSuggestionBuiltinDefinition); - } - if (argType === 'boolean') { - // suggest IS, NOT and TRUE/FALSE - return [ - ...compatibleFunctions - .filter(({ name }) => name === 'in') - .map(getSuggestionBuiltinDefinition), - ...buildConstantsDefinitions(['true', 'false']), - ]; - } - return []; -}; - -export const getBuiltinCompatibleFunctionDefinition = ( - command: string, - option: string | undefined, - argType: FunctionParameterType, - returnTypes?: FunctionReturnType[], - { skipAssign, commandsToInclude }: { skipAssign?: boolean; commandsToInclude?: string[] } = {} -): SuggestionRawDefinition[] => { - const compatibleFunctions = [...builtinFunctions, ...getTestFunctions()].filter( - ({ name, supportedCommands, supportedOptions, signatures, ignoreAsSuggestion }) => - (command === 'where' && commandsToInclude ? commandsToInclude.indexOf(name) > -1 : true) && - !ignoreAsSuggestion && - (!skipAssign || name !== '=') && - (option ? supportedOptions?.includes(option) : supportedCommands.includes(command)) && - signatures.some( - ({ params }) => - !params.length || params.some((pArg) => pArg.type === argType || pArg.type === 'any') - ) - ); - if (!returnTypes) { - return compatibleFunctions.map(getSuggestionBuiltinDefinition); - } - return compatibleFunctions - .filter((mathDefinition) => - mathDefinition.signatures.some( - (signature) => - returnTypes[0] === 'unknown' || - returnTypes[0] === 'any' || - returnTypes.includes(signature.returnType) - ) - ) - .map(getSuggestionBuiltinDefinition); -}; - export const getCommandAutocompleteDefinitions = ( commands: Array> ): SuggestionRawDefinition[] => diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts index 9b7e2b0bf71a..d9813bb0e91a 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts @@ -20,6 +20,7 @@ import { CommandDefinition, CommandOptionsDefinition, CommandModeDefinition, + FunctionParameterType, } from '../definitions/types'; import { shouldBeQuotedSource, getCommandDefinition, shouldBeQuotedText } from '../shared/helpers'; import { buildDocumentation, buildFunctionDocumentation } from './documentation_util'; @@ -27,6 +28,14 @@ import { DOUBLE_BACKTICK, SINGLE_TICK_REGEX } from '../shared/constants'; import { ESQLRealField } from '../validation/types'; import { isNumericType } from '../shared/esql_types'; import { getTestFunctions } from '../shared/test_functions'; +import { builtinFunctions } from '../definitions/builtin'; + +const techPreviewLabel = i18n.translate( + 'kbn-esql-validation-autocomplete.esql.autocomplete.techPreviewLabel', + { + defaultMessage: `Technical Preview`, + } +); const allFunctions = memoize( () => @@ -58,13 +67,17 @@ function getSafeInsertSourceText(text: string) { } export function getFunctionSuggestion(fn: FunctionDefinition): SuggestionRawDefinition { + let detail = fn.description; + if (fn.preview) { + detail = `[${techPreviewLabel}] ${detail}`; + } const fullSignatures = getFunctionSignatures(fn, { capitalize: true, withTypes: true }); return { label: fn.name.toUpperCase(), text: `${fn.name.toUpperCase()}($0)`, asSnippet: true, kind: 'Function', - detail: fn.description, + detail, documentation: { value: buildFunctionDocumentation(fullSignatures, fn.examples), }, @@ -75,7 +88,7 @@ export function getFunctionSuggestion(fn: FunctionDefinition): SuggestionRawDefi }; } -export function getSuggestionBuiltinDefinition(fn: FunctionDefinition): SuggestionRawDefinition { +export function getOperatorSuggestion(fn: FunctionDefinition): SuggestionRawDefinition { const hasArgs = fn.signatures.some(({ params }) => params.length > 1); return { label: fn.name.toUpperCase(), @@ -91,21 +104,22 @@ export function getSuggestionBuiltinDefinition(fn: FunctionDefinition): Suggesti }; } -/** - * Builds suggestions for functions based on the provided predicates. - * - * @param predicates a set of conditions that must be met for a function to be included in the suggestions - * @returns - */ -export const getFunctionSuggestions = (predicates?: { +interface FunctionFilterPredicates { command?: string; option?: string | undefined; returnTypes?: string[]; ignored?: string[]; -}): SuggestionRawDefinition[] => { - const functions = allFunctions(); - const { command, option, returnTypes, ignored = [] } = predicates ?? {}; - const filteredFunctions: FunctionDefinition[] = functions.filter( +} + +export const filterFunctionDefinitions = ( + functions: FunctionDefinition[], + predicates: FunctionFilterPredicates | undefined +): FunctionDefinition[] => { + if (!predicates) { + return functions; + } + const { command, option, returnTypes, ignored = [] } = predicates; + return functions.filter( ({ name, supportedCommands, supportedOptions, ignoreAsSuggestion, signatures }) => { if (ignoreAsSuggestion) { return false; @@ -130,8 +144,53 @@ export const getFunctionSuggestions = (predicates?: { return true; } ); +}; + +/** + * Builds suggestions for functions based on the provided predicates. + * + * @param predicates a set of conditions that must be met for a function to be included in the suggestions + * @returns + */ +export const getFunctionSuggestions = ( + predicates?: FunctionFilterPredicates +): SuggestionRawDefinition[] => { + return filterFunctionDefinitions(allFunctions(), predicates).map(getFunctionSuggestion); +}; + +/** + * Builds suggestions for operators based on the provided predicates. + * + * @param predicates a set of conditions that must be met for an operator to be included in the suggestions + * @returns + */ +export const getOperatorSuggestions = ( + predicates?: FunctionFilterPredicates & { leftParamType?: FunctionParameterType } +): SuggestionRawDefinition[] => { + const filteredDefinitions = filterFunctionDefinitions( + getTestFunctions().length ? [...builtinFunctions, ...getTestFunctions()] : builtinFunctions, + predicates + ); + + // make sure the operator has at least one signature that matches + // the type of the existing left argument if provided (e.g. "doubleField ") + return ( + predicates?.leftParamType + ? filteredDefinitions.filter(({ signatures }) => + signatures.some( + ({ params }) => + !params.length || + params.some((pArg) => pArg.type === predicates?.leftParamType || pArg.type === 'any') + ) + ) + : filteredDefinitions + ).map(getOperatorSuggestion); +}; - return filteredFunctions.map(getFunctionSuggestion); +export const getSuggestionsAfterNot = (): SuggestionRawDefinition[] => { + return builtinFunctions + .filter(({ name }) => name === 'like' || name === 'rlike' || name === 'in') + .map(getOperatorSuggestion); }; export function getSuggestionCommandDefinition( diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.test.ts new file mode 100644 index 000000000000..c4133592c425 --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.test.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 { getOverlapRange } from './helper'; + +describe('getOverlapRange', () => { + it('should return the overlap range', () => { + expect(getOverlapRange('IS N', 'IS NOT NULL')).toEqual({ start: 1, end: 5 }); + expect(getOverlapRange('I', 'IS NOT NULL')).toEqual({ start: 1, end: 2 }); + }); + + it('full query', () => { + expect(getOverlapRange('FROM index | WHERE field IS N', 'IS NOT NULL')).toEqual({ + start: 26, + end: 30, + }); + }); +}); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts index 9724878611b0..67ea324a1a69 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts @@ -15,18 +15,22 @@ import type { ESQLSource, } from '@kbn/esql-ast'; import { uniqBy } from 'lodash'; -import type { - FunctionDefinition, - FunctionReturnType, - SupportedDataType, +import { + isParameterType, + type FunctionDefinition, + type FunctionReturnType, + type SupportedDataType, + isReturnType, } from '../definitions/types'; import { findFinalWord, getColumnForASTNode, getFunctionDefinition, + isArrayType, isAssignment, isColumnItem, isFunctionItem, + isIdentifier, isLiteralItem, isTimeIntervalItem, } from '../shared/helpers'; @@ -38,9 +42,12 @@ import { getFunctionSuggestions, getCompatibleLiterals, getDateLiterals, + getOperatorSuggestions, } from './factories'; import { EDITOR_MARKER } from '../shared/constants'; import { ESQLRealField, ESQLVariable, ReferenceMaps } from '../validation/types'; +import { listCompleteItem } from './complete_items'; +import { removeMarkerArgFromArgsList } from '../shared/context'; function extractFunctionArgs(args: ESQLAstItem[]): ESQLFunction[] { return args.flatMap((arg) => (isAssignment(arg) ? arg.args[1] : arg)).filter(isFunctionItem); @@ -207,9 +214,10 @@ export function getOverlapRange( } } + // add one since Monaco columns are 1-based return { - start: Math.min(query.length - overlapLength + 1, query.length), - end: query.length, + start: query.length - overlapLength + 1, + end: query.length + 1, }; } @@ -444,6 +452,7 @@ export function pushItUpInTheList(suggestions: SuggestionRawDefinition[], should })); } +/** @deprecated — use getExpressionType instead (packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts) */ export function extractTypeFromASTArg( arg: ESQLAstItem, references: Pick @@ -457,15 +466,13 @@ export function extractTypeFromASTArg( if (Array.isArray(arg)) { return extractTypeFromASTArg(arg[0], references); } - if (isColumnItem(arg) || isLiteralItem(arg)) { - if (isLiteralItem(arg)) { - return arg.literalType; - } - if (isColumnItem(arg)) { - const hit = getColumnForASTNode(arg, references); - if (hit) { - return hit.type; - } + if (isLiteralItem(arg)) { + return arg.literalType; + } + if (isColumnItem(arg) || isIdentifier(arg)) { + const hit = getColumnForASTNode(arg, references); + if (hit) { + return hit.type; } } if (isTimeIntervalItem(arg)) { @@ -480,3 +487,182 @@ export function extractTypeFromASTArg( } } } + +// @TODO: refactor this to be shared with validation +export function checkFunctionInvocationComplete( + func: ESQLFunction, + getExpressionType: (expression: ESQLAstItem) => SupportedDataType | 'unknown' +): { + complete: boolean; + reason?: 'tooFewArgs' | 'wrongTypes'; +} { + const fnDefinition = getFunctionDefinition(func.name); + if (!fnDefinition) { + return { complete: false }; + } + const cleanedArgs = removeMarkerArgFromArgsList(func)!.args; + const argLengthCheck = fnDefinition.signatures.some((def) => { + if (def.minParams && cleanedArgs.length >= def.minParams) { + return true; + } + if (cleanedArgs.length === def.params.length) { + return true; + } + return cleanedArgs.length >= def.params.filter(({ optional }) => !optional).length; + }); + if (!argLengthCheck) { + return { complete: false, reason: 'tooFewArgs' }; + } + if (fnDefinition.name === 'in' && Array.isArray(func.args[1]) && !func.args[1].length) { + return { complete: false, reason: 'tooFewArgs' }; + } + const hasCorrectTypes = fnDefinition.signatures.some((def) => { + return func.args.every((a, index) => { + return ( + (fnDefinition.name.endsWith('null') && def.params[index].type === 'any') || + def.params[index].type === getExpressionType(a) + ); + }); + }); + if (!hasCorrectTypes) { + return { complete: false, reason: 'wrongTypes' }; + } + return { complete: true }; +} + +/** + * This function is used to + * - suggest the next argument for an incomplete or incorrect binary operator expression (e.g. field > ) + * - suggest an operator to the right of a complete binary operator expression (e.g. field > 0 ) + * - suggest an operator to the right of a complete unary operator (e.g. field IS NOT NULL ) + * + * TODO — is this function doing too much? + */ +export async function getSuggestionsToRightOfOperatorExpression({ + queryText, + commandName, + optionName, + rootOperator: operator, + preferredExpressionType, + getExpressionType, + getColumnsByType, +}: { + queryText: string; + commandName: string; + optionName?: string; + rootOperator: ESQLFunction; + preferredExpressionType?: SupportedDataType; + getExpressionType: (expression: ESQLAstItem) => SupportedDataType | 'unknown'; + getColumnsByType: GetColumnsByTypeFn; +}) { + const suggestions = []; + const isFnComplete = checkFunctionInvocationComplete(operator, getExpressionType); + if (isFnComplete.complete) { + // i.e. ... | field > 0 + // i.e. ... | field + otherN + const operatorReturnType = getExpressionType(operator); + suggestions.push( + ...getOperatorSuggestions({ + command: commandName, + option: optionName, + // here we use the operator return type because we're suggesting operators that could + // accept the result of the existing operator as a left operand + leftParamType: + operatorReturnType === 'unknown' || operatorReturnType === 'unsupported' + ? 'any' + : operatorReturnType, + ignored: ['='], + }) + ); + } else { + // i.e. ... | field >= + // i.e. ... | field + + // i.e. ... | field and + + // Because it's an incomplete function, need to extract the type of the current argument + // and suggest the next argument based on types + + // pick the last arg and check its type to verify whether is incomplete for the given function + const cleanedArgs = removeMarkerArgFromArgsList(operator)!.args; + const leftArgType = getExpressionType(operator.args[cleanedArgs.length - 1]); + + if (isFnComplete.reason === 'tooFewArgs') { + const fnDef = getFunctionDefinition(operator.name); + if ( + fnDef?.signatures.every(({ params }) => + params.some(({ type }) => isArrayType(type as string)) + ) + ) { + suggestions.push(listCompleteItem); + } else { + const finalType = leftArgType || leftArgType || 'any'; + const supportedTypes = getSupportedTypesForBinaryOperators(fnDef, finalType as string); + + // this is a special case with AND/OR + // expression AND/OR + // technically another boolean value should be suggested, but it is a better experience + // to actually suggest a wider set of fields/functions + const typeToUse = + finalType === 'boolean' && getFunctionDefinition(operator.name)?.type === 'builtin' + ? ['any'] + : (supportedTypes as string[]); + + // TODO replace with fields callback + function suggestions + suggestions.push( + ...(await getFieldsOrFunctionsSuggestions( + typeToUse, + commandName, + optionName, + getColumnsByType, + { + functions: true, + fields: true, + } + )) + ); + } + } + + /** + * If the caller has supplied a preferred expression type, we can suggest operators that + * would move the user toward that expression type. + * + * e.g. if we have a preferred type of boolean and we have `timestamp > "2002" AND doubleField` + * this is an incorrect signature for AND because the left side is boolean and the right side is double + * + * Knowing that we prefer boolean expressions, we suggest operators that would accept doubleField as a left operand + * and also return a boolean value. + * + * I believe this is only used in WHERE and probably bears some rethinking. + */ + if (isFnComplete.reason === 'wrongTypes') { + if (leftArgType && preferredExpressionType) { + // suggest something to complete the operator + if ( + leftArgType !== preferredExpressionType && + isParameterType(leftArgType) && + isReturnType(preferredExpressionType) + ) { + suggestions.push( + ...getOperatorSuggestions({ + command: commandName, + leftParamType: leftArgType, + returnTypes: [preferredExpressionType], + }) + ); + } + } + } + } + return suggestions.map((s) => { + const overlap = getOverlapRange(queryText, s.text); + const offset = overlap.start === overlap.end ? 1 : 0; + return { + ...s, + rangeToReplace: { + start: overlap.start + offset, + end: overlap.end + offset, + }, + }; + }); +} diff --git a/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.ts b/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.ts index 37ab56350ffb..7c9d5d7ae8ba 100644 --- a/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.ts +++ b/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.ts @@ -20,6 +20,7 @@ import { getAllFunctions, getCommandDefinition, isColumnItem, + isIdentifier, isSourceItem, shouldBeQuotedText, } from '../shared/helpers'; @@ -138,7 +139,7 @@ function extractUnquotedFieldText( if (errorType === 'syntaxError') { // scope it down to column items for now const { node } = getAstContext(query, ast, possibleStart - 1); - if (node && isColumnItem(node)) { + if (node && (isColumnItem(node) || isIdentifier(node))) { return { start: node.location.min + 1, name: query.substring(node.location.min, end).trimEnd(), @@ -379,7 +380,7 @@ function inferCodeFromError( if (error.message.startsWith('SyntaxError: token recognition error at:')) { // scope it down to column items for now const { node } = getAstContext(rawText, ast, error.startColumn - 2); - return node && isColumnItem(node) ? 'quotableFields' : undefined; + return node && (isColumnItem(node) || isIdentifier(node)) ? 'quotableFields' : undefined; } } diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/builtin.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/builtin.ts index e71ed32e4c79..3f5040efbcb1 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/builtin.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/builtin.ts @@ -528,7 +528,7 @@ const inFunctions: FunctionDefinition[] = [ ], })); -const logicFunctions: FunctionDefinition[] = [ +export const logicalOperators: FunctionDefinition[] = [ { name: 'and', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.andDoc', { @@ -649,7 +649,7 @@ export const builtinFunctions: FunctionDefinition[] = [ ...comparisonFunctions, ...likeFunctions, ...inFunctions, - ...logicFunctions, + ...logicalOperators, ...nullFunctions, ...otherDefinitions, ]; diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/commands.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/commands.ts index d07511665ad3..950dac5e2d50 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/commands.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/commands.ts @@ -20,6 +20,7 @@ import { isAssignment, isColumnItem, isFunctionItem, + isFunctionOperatorParam, isLiteralItem, } from '../shared/helpers'; import { ENRICH_MODES } from './settings'; @@ -36,6 +37,7 @@ import { suggest as suggestForSort } from '../autocomplete/commands/sort'; import { suggest as suggestForKeep } from '../autocomplete/commands/keep'; import { suggest as suggestForDrop } from '../autocomplete/commands/drop'; import { suggest as suggestForStats } from '../autocomplete/commands/stats'; +import { suggest as suggestForWhere } from '../autocomplete/commands/where'; const statsValidator = (command: ESQLCommand) => { const messages: ESQLMessage[] = []; @@ -72,7 +74,7 @@ const statsValidator = (command: ESQLCommand) => { function checkAggExistence(arg: ESQLFunction): boolean { // TODO the grouping function check may not // hold true for all future cases - if (isAggFunction(arg)) { + if (isAggFunction(arg) || isFunctionOperatorParam(arg)) { return true; } if (isOtherFunction(arg)) { @@ -313,7 +315,8 @@ export const commandDefinitions: Array> = [ { name: 'keep', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.keepDoc', { - defaultMessage: 'Rearranges fields in the input table by applying the keep clauses in fields', + defaultMessage: + 'Rearranges fields in the Results table by applying the keep clauses in fields', }), examples: ['… | keep a', '… | keep a,b'], suggest: suggestForKeep, @@ -409,6 +412,7 @@ export const commandDefinitions: Array> = [ }, options: [], modes: [], + suggest: suggestForWhere, }, { name: 'dissect', diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/generated/aggregation_functions.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/generated/aggregation_functions.ts index f73521ddf3a8..6a429f2288f9 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/generated/aggregation_functions.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/generated/aggregation_functions.ts @@ -36,6 +36,7 @@ const avgDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.avg', { defaultMessage: 'The average of a numeric field.', }), + preview: false, alias: undefined, signatures: [ { @@ -85,6 +86,7 @@ const countDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.count', { defaultMessage: 'Returns the total number (count) of input values.', }), + preview: false, alias: undefined, signatures: [ { @@ -228,6 +230,7 @@ const countDistinctDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.count_distinct', { defaultMessage: 'Returns the approximate number of distinct values.', }), + preview: false, alias: undefined, signatures: [ { @@ -743,6 +746,7 @@ const maxDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.max', { defaultMessage: 'The maximum value of a field.', }), + preview: false, alias: undefined, signatures: [ { @@ -853,6 +857,7 @@ const medianDefinition: FunctionDefinition = { defaultMessage: 'The value that is greater than half of all values and less than half of all values, also known as the 50% `PERCENTILE`.', }), + preview: false, alias: undefined, signatures: [ { @@ -906,6 +911,7 @@ const medianAbsoluteDeviationDefinition: FunctionDefinition = { "Returns the median absolute deviation, a measure of variability. It is a robust statistic, meaning that it is useful for describing data that may have outliers, or may not be normally distributed. For such data it can be more descriptive than standard deviation.\n\nIt is calculated as the median of each data point's deviation from the median of the entire sample. That is, for a random variable `X`, the median absolute deviation is `median(|median(X) - X|)`.", } ), + preview: false, alias: undefined, signatures: [ { @@ -955,6 +961,7 @@ const minDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.min', { defaultMessage: 'The minimum value of a field.', }), + preview: false, alias: undefined, signatures: [ { @@ -1065,6 +1072,7 @@ const percentileDefinition: FunctionDefinition = { defaultMessage: 'Returns the value at which a certain percentage of observed values occur. For example, the 95th percentile is the value which is greater than 95% of the observed values and the 50th percentile is the `MEDIAN`.', }), + preview: false, alias: undefined, signatures: [ { @@ -1228,6 +1236,7 @@ const stCentroidAggDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_centroid_agg', { defaultMessage: 'Calculate the spatial centroid over a field with spatial point geometry type.', }), + preview: false, alias: undefined, signatures: [ { @@ -1264,6 +1273,7 @@ const sumDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.sum', { defaultMessage: 'The sum of a numeric expression.', }), + preview: false, alias: undefined, signatures: [ { @@ -1313,6 +1323,7 @@ const topDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.top', { defaultMessage: 'Collects the top values for a field. Includes repeated values.', }), + preview: false, alias: undefined, signatures: [ { @@ -1510,6 +1521,7 @@ const valuesDefinition: FunctionDefinition = { defaultMessage: "Returns all values in a group as a multivalued field. The order of the returned values isn't guaranteed. If you need the values returned in order use esql-mv_sort.", }), + preview: true, alias: undefined, signatures: [ { @@ -1618,6 +1630,7 @@ const weightedAvgDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.weighted_avg', { defaultMessage: 'The weighted average of a numeric expression.', }), + preview: false, alias: undefined, signatures: [ { diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts index 4b0ea8ee564e..7e9019aeb905 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts @@ -38,6 +38,7 @@ const absDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.abs', { defaultMessage: 'Returns the absolute value.', }), + preview: false, alias: undefined, signatures: [ { @@ -97,6 +98,7 @@ const acosDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.acos', { defaultMessage: 'Returns the arccosine of `n` as an angle, expressed in radians.', }), + preview: false, alias: undefined, signatures: [ { @@ -154,6 +156,7 @@ const asinDefinition: FunctionDefinition = { defaultMessage: 'Returns the arcsine of the input\nnumeric expression as an angle, expressed in radians.', }), + preview: false, alias: undefined, signatures: [ { @@ -211,6 +214,7 @@ const atanDefinition: FunctionDefinition = { defaultMessage: 'Returns the arctangent of the input\nnumeric expression as an angle, expressed in radians.', }), + preview: false, alias: undefined, signatures: [ { @@ -268,6 +272,7 @@ const atan2Definition: FunctionDefinition = { defaultMessage: 'The angle between the positive x-axis and the ray from the\norigin to the point (x , y) in the Cartesian plane, expressed in radians.', }), + preview: false, alias: undefined, signatures: [ { @@ -526,6 +531,7 @@ const categorizeDefinition: FunctionDefinition = { }), ignoreAsSuggestion: true, + preview: false, alias: undefined, signatures: [ { @@ -563,6 +569,7 @@ const cbrtDefinition: FunctionDefinition = { defaultMessage: 'Returns the cube root of a number. The input can be any numeric value, the return value is always a double.\nCube roots of infinities are null.', }), + preview: false, alias: undefined, signatures: [ { @@ -619,6 +626,7 @@ const ceilDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.ceil', { defaultMessage: 'Round a number up to the nearest integer.', }), + preview: false, alias: undefined, signatures: [ { @@ -676,6 +684,7 @@ const cidrMatchDefinition: FunctionDefinition = { defaultMessage: 'Returns true if the provided IP is contained in one of the provided CIDR blocks.', }), + preview: false, alias: undefined, signatures: [ { @@ -727,6 +736,7 @@ const coalesceDefinition: FunctionDefinition = { defaultMessage: 'Returns the first of its arguments that is not null. If all arguments are null, it returns `null`.', }), + preview: false, alias: undefined, signatures: [ { @@ -990,6 +1000,7 @@ const concatDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.concat', { defaultMessage: 'Concatenates two or more strings.', }), + preview: false, alias: undefined, signatures: [ { @@ -1072,6 +1083,7 @@ const cosDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.cos', { defaultMessage: 'Returns the cosine of an angle.', }), + preview: false, alias: undefined, signatures: [ { @@ -1128,6 +1140,7 @@ const coshDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.cosh', { defaultMessage: 'Returns the hyperbolic cosine of a number.', }), + preview: false, alias: undefined, signatures: [ { @@ -1185,6 +1198,7 @@ const dateDiffDefinition: FunctionDefinition = { defaultMessage: 'Subtracts the `startTimestamp` from the `endTimestamp` and returns the difference in multiples of `unit`.\nIf `startTimestamp` is later than the `endTimestamp`, negative values are returned.', }), + preview: false, alias: undefined, signatures: [ { @@ -1294,7 +1308,7 @@ const dateDiffDefinition: FunctionDefinition = { validate: undefined, examples: [ 'ROW date1 = TO_DATETIME("2023-12-02T11:00:00.000Z"), date2 = TO_DATETIME("2023-12-02T11:00:00.001Z")\n| EVAL dd_ms = DATE_DIFF("microseconds", date1, date2)', - 'ROW end_23="2023-12-31T23:59:59.999Z"::DATETIME,\n start_24="2024-01-01T00:00:00.000Z"::DATETIME,\n end_24="2024-12-31T23:59:59.999"::DATETIME\n| EVAL end23_to_start24=DATE_DIFF("year", end_23, start_24)\n| EVAL end23_to_end24=DATE_DIFF("year", end_23, end_24)\n| EVAL start_to_end_24=DATE_DIFF("year", start_24, end_24)', + 'ROW end_23=TO_DATETIME("2023-12-31T23:59:59.999Z"),\n start_24=TO_DATETIME("2024-01-01T00:00:00.000Z"),\n end_24=TO_DATETIME("2024-12-31T23:59:59.999")\n| EVAL end23_to_start24=DATE_DIFF("year", end_23, start_24)\n| EVAL end23_to_end24=DATE_DIFF("year", end_23, end_24)\n| EVAL start_to_end_24=DATE_DIFF("year", start_24, end_24)', ], }; @@ -1305,6 +1319,7 @@ const dateExtractDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.date_extract', { defaultMessage: 'Extracts parts of a date, like year, month, day, hour.', }), + preview: false, alias: undefined, signatures: [ { @@ -1386,6 +1401,7 @@ const dateFormatDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.date_format', { defaultMessage: 'Returns a string representation of a date, in the provided format.', }), + preview: false, alias: undefined, signatures: [ { @@ -1435,6 +1451,7 @@ const dateParseDefinition: FunctionDefinition = { defaultMessage: 'Returns a date by parsing the second argument using the format specified in the first argument.', }), + preview: false, alias: undefined, signatures: [ { @@ -1511,6 +1528,7 @@ const dateTruncDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.date_trunc', { defaultMessage: 'Rounds down a date to the closest interval.', }), + preview: false, alias: undefined, signatures: [ { @@ -1561,6 +1579,7 @@ const eDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.e', { defaultMessage: "Returns Euler's number.", }), + preview: false, alias: undefined, signatures: [ { @@ -1582,6 +1601,7 @@ const endsWithDefinition: FunctionDefinition = { defaultMessage: 'Returns a boolean that indicates whether a keyword string ends with another string.', }), + preview: false, alias: undefined, signatures: [ { @@ -1658,6 +1678,7 @@ const expDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.exp', { defaultMessage: 'Returns the value of e raised to the power of the given number.', }), + preview: false, alias: undefined, signatures: [ { @@ -1714,6 +1735,7 @@ const floorDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.floor', { defaultMessage: 'Round a number down to the nearest integer.', }), + preview: false, alias: undefined, signatures: [ { @@ -1770,6 +1792,7 @@ const fromBase64Definition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.from_base64', { defaultMessage: 'Decode a base64 string.', }), + preview: false, alias: undefined, signatures: [ { @@ -1807,6 +1830,7 @@ const greatestDefinition: FunctionDefinition = { defaultMessage: 'Returns the maximum value from multiple columns. This is similar to `MV_MAX`\nexcept it is intended to run on multiple columns at once.', }), + preview: false, alias: undefined, signatures: [ { @@ -2023,6 +2047,7 @@ const hypotDefinition: FunctionDefinition = { defaultMessage: 'Returns the hypotenuse of two numbers. The input can be any numeric values, the return value is always a double.\nHypotenuses of infinities are null.', }), + preview: false, alias: undefined, signatures: [ { @@ -2279,6 +2304,7 @@ const ipPrefixDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.ip_prefix', { defaultMessage: 'Truncates an IP to a given prefix length.', }), + preview: false, alias: undefined, signatures: [ { @@ -2318,6 +2344,7 @@ const leastDefinition: FunctionDefinition = { defaultMessage: 'Returns the minimum value from multiple columns. This is similar to `MV_MIN` except it is intended to run on multiple columns at once.', }), + preview: false, alias: undefined, signatures: [ { @@ -2534,6 +2561,7 @@ const leftDefinition: FunctionDefinition = { defaultMessage: "Returns the substring that extracts 'length' chars from 'string' starting from the left.", }), + preview: false, alias: undefined, signatures: [ { @@ -2582,6 +2610,7 @@ const lengthDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.length', { defaultMessage: 'Returns the character length of a string.', }), + preview: false, alias: undefined, signatures: [ { @@ -2619,6 +2648,7 @@ const locateDefinition: FunctionDefinition = { defaultMessage: 'Returns an integer that indicates the position of a keyword substring within another string.\nReturns `0` if the substring cannot be found.\nNote that string positions start from `1`.', }), + preview: false, alias: undefined, signatures: [ { @@ -2776,6 +2806,7 @@ const logDefinition: FunctionDefinition = { defaultMessage: 'Returns the logarithm of a value to a base. The input can be any numeric value, the return value is always a double.\n\nLogs of zero, negative numbers, and base of one return `null` as well as a warning.', }), + preview: false, alias: undefined, signatures: [ { @@ -3099,6 +3130,7 @@ const log10Definition: FunctionDefinition = { defaultMessage: 'Returns the logarithm of a value to base 10. The input can be any numeric value, the return value is always a double.\n\nLogs of 0 and negative numbers return `null` as well as a warning.', }), + preview: false, alias: undefined, signatures: [ { @@ -3178,6 +3210,7 @@ const ltrimDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.ltrim', { defaultMessage: 'Removes leading whitespaces from a string.', }), + preview: false, alias: undefined, signatures: [ { @@ -3217,6 +3250,7 @@ const matchDefinition: FunctionDefinition = { defaultMessage: 'Performs a match query on the specified field. Returns true if the provided query matches the row.', }), + preview: true, alias: undefined, signatures: [ { @@ -3295,6 +3329,7 @@ const mvAppendDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_append', { defaultMessage: 'Concatenates values of two multi-value fields.', }), + preview: false, alias: undefined, signatures: [ { @@ -3507,6 +3542,7 @@ const mvAvgDefinition: FunctionDefinition = { defaultMessage: 'Converts a multivalued field into a single valued field containing the average of all of the values.', }), + preview: false, alias: undefined, signatures: [ { @@ -3564,6 +3600,7 @@ const mvConcatDefinition: FunctionDefinition = { defaultMessage: 'Converts a multivalued string expression into a single valued column containing the concatenation of all values separated by a delimiter.', }), + preview: false, alias: undefined, signatures: [ { @@ -3644,6 +3681,7 @@ const mvCountDefinition: FunctionDefinition = { defaultMessage: 'Converts a multivalued expression into a single valued column containing a count of the number of values.', }), + preview: false, alias: undefined, signatures: [ { @@ -3800,6 +3838,7 @@ const mvDedupeDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_dedupe', { defaultMessage: 'Remove duplicate values from a multivalued field.', }), + preview: false, alias: undefined, signatures: [ { @@ -3947,6 +3986,7 @@ const mvFirstDefinition: FunctionDefinition = { defaultMessage: 'Converts a multivalued expression into a single valued column containing the\nfirst value. This is most useful when reading from a function that emits\nmultivalued columns in a known order like `SPLIT`.', }), + preview: false, alias: undefined, signatures: [ { @@ -4104,6 +4144,7 @@ const mvLastDefinition: FunctionDefinition = { defaultMessage: 'Converts a multivalue expression into a single valued column containing the last\nvalue. This is most useful when reading from a function that emits multivalued\ncolumns in a known order like `SPLIT`.', }), + preview: false, alias: undefined, signatures: [ { @@ -4261,6 +4302,7 @@ const mvMaxDefinition: FunctionDefinition = { defaultMessage: 'Converts a multivalued expression into a single valued column containing the maximum value.', }), + preview: false, alias: undefined, signatures: [ { @@ -4381,6 +4423,7 @@ const mvMedianDefinition: FunctionDefinition = { defaultMessage: 'Converts a multivalued field into a single valued field containing the median value.', }), + preview: false, alias: undefined, signatures: [ { @@ -4444,6 +4487,7 @@ const mvMedianAbsoluteDeviationDefinition: FunctionDefinition = { "Converts a multivalued field into a single valued field containing the median absolute deviation.\n\nIt is calculated as the median of each data point's deviation from the median of the entire sample. That is, for a random variable `X`, the median absolute deviation is `median(|median(X) - X|)`.", } ), + preview: false, alias: undefined, signatures: [ { @@ -4503,6 +4547,7 @@ const mvMinDefinition: FunctionDefinition = { defaultMessage: 'Converts a multivalued expression into a single valued column containing the minimum value.', }), + preview: false, alias: undefined, signatures: [ { @@ -4623,6 +4668,7 @@ const mvPercentileDefinition: FunctionDefinition = { defaultMessage: 'Converts a multivalued field into a single valued field containing the value at which a certain percentage of observed values occur.', }), + preview: false, alias: undefined, signatures: [ { @@ -4780,6 +4826,7 @@ const mvPseriesWeightedSumDefinition: FunctionDefinition = { 'Converts a multivalued expression into a single-valued column by multiplying every element on the input list by its corresponding term in P-Series and computing the sum.', } ), + preview: false, alias: undefined, signatures: [ { @@ -4814,6 +4861,7 @@ const mvSliceDefinition: FunctionDefinition = { defaultMessage: 'Returns a subset of the multivalued field using the start and end index values.\nThis is most useful when reading from a function that emits multivalued columns\nin a known order like `SPLIT` or `MV_SORT`.', }), + preview: false, alias: undefined, signatures: [ { @@ -5093,6 +5141,7 @@ const mvSortDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_sort', { defaultMessage: 'Sorts a multivalued field in lexicographical order.', }), + preview: false, alias: undefined, signatures: [ { @@ -5254,6 +5303,7 @@ const mvSumDefinition: FunctionDefinition = { defaultMessage: 'Converts a multivalued field into a single valued field containing the sum of all of the values.', }), + preview: false, alias: undefined, signatures: [ { @@ -5311,6 +5361,7 @@ const mvZipDefinition: FunctionDefinition = { defaultMessage: 'Combines the values from two multivalued fields with a delimiter that joins them together.', }), + preview: false, alias: undefined, signatures: [ { @@ -5549,6 +5600,7 @@ const nowDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.now', { defaultMessage: 'Returns current date and time.', }), + preview: false, alias: undefined, signatures: [ { @@ -5569,6 +5621,7 @@ const piDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.pi', { defaultMessage: "Returns Pi, the ratio of a circle's circumference to its diameter.", }), + preview: false, alias: undefined, signatures: [ { @@ -5589,6 +5642,7 @@ const powDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.pow', { defaultMessage: 'Returns the value of `base` raised to the power of `exponent`.', }), + preview: false, alias: undefined, signatures: [ { @@ -5849,6 +5903,7 @@ const qstrDefinition: FunctionDefinition = { defaultMessage: 'Performs a query string query. Returns true if the provided query string matches the row.', }), + preview: true, alias: undefined, signatures: [ { @@ -5888,6 +5943,7 @@ const repeatDefinition: FunctionDefinition = { defaultMessage: 'Returns a string constructed by concatenating `string` with itself the specified `number` of times.', }), + preview: false, alias: undefined, signatures: [ { @@ -5924,7 +5980,7 @@ const repeatDefinition: FunctionDefinition = { supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'], supportedOptions: ['by'], validate: undefined, - examples: ['ROW a = "Hello!"\n| EVAL triple_a = REPEAT(a, 3);'], + examples: ['ROW a = "Hello!"\n| EVAL triple_a = REPEAT(a, 3)'], }; // Do not edit this manually... generated by scripts/generate_function_definitions.ts @@ -5935,6 +5991,7 @@ const replaceDefinition: FunctionDefinition = { defaultMessage: 'The function substitutes in the string `str` any match of the regular expression `regex`\nwith the replacement string `newStr`.', }), + preview: false, alias: undefined, signatures: [ { @@ -6111,6 +6168,7 @@ const reverseDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.reverse', { defaultMessage: 'Returns a new string representing the input string in reverse order.', }), + preview: false, alias: undefined, signatures: [ { @@ -6151,6 +6209,7 @@ const rightDefinition: FunctionDefinition = { defaultMessage: "Return the substring that extracts 'length' chars from 'str' starting from the right.", }), + preview: false, alias: undefined, signatures: [ { @@ -6200,6 +6259,7 @@ const roundDefinition: FunctionDefinition = { defaultMessage: 'Rounds a number to the specified number of decimal places.\nDefaults to 0, which returns the nearest integer. If the\nprecision is a negative number, rounds to the number of digits left\nof the decimal point.', }), + preview: false, alias: undefined, signatures: [ { @@ -6303,6 +6363,7 @@ const rtrimDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.rtrim', { defaultMessage: 'Removes trailing whitespaces from a string.', }), + preview: false, alias: undefined, signatures: [ { @@ -6342,6 +6403,7 @@ const signumDefinition: FunctionDefinition = { defaultMessage: 'Returns the sign of the given number.\nIt returns `-1` for negative numbers, `0` for `0` and `1` for positive numbers.', }), + preview: false, alias: undefined, signatures: [ { @@ -6398,6 +6460,7 @@ const sinDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.sin', { defaultMessage: 'Returns the sine of an angle.', }), + preview: false, alias: undefined, signatures: [ { @@ -6454,6 +6517,7 @@ const sinhDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.sinh', { defaultMessage: 'Returns the hyperbolic sine of a number.', }), + preview: false, alias: undefined, signatures: [ { @@ -6510,6 +6574,7 @@ const spaceDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.space', { defaultMessage: 'Returns a string made of `number` spaces.', }), + preview: false, alias: undefined, signatures: [ { @@ -6536,6 +6601,7 @@ const splitDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.split', { defaultMessage: 'Split a single valued string into multiple strings.', }), + preview: false, alias: undefined, signatures: [ { @@ -6613,6 +6679,7 @@ const sqrtDefinition: FunctionDefinition = { defaultMessage: 'Returns the square root of a number. The input can be any numeric value, the return value is always a double.\nSquare roots of negative numbers and infinities are null.', }), + preview: false, alias: undefined, signatures: [ { @@ -6670,6 +6737,7 @@ const stContainsDefinition: FunctionDefinition = { defaultMessage: 'Returns whether the first geometry contains the second geometry.\nThis is the inverse of the `ST_WITHIN` function.', }), + preview: false, alias: undefined, signatures: [ { @@ -6809,6 +6877,7 @@ const stDisjointDefinition: FunctionDefinition = { defaultMessage: 'Returns whether the two geometries or geometry columns are disjoint.\nThis is the inverse of the `ST_INTERSECTS` function.\nIn mathematical terms: ST_Disjoint(A, B) ⇔ A ⋂ B = ∅', }), + preview: false, alias: undefined, signatures: [ { @@ -6948,6 +7017,7 @@ const stDistanceDefinition: FunctionDefinition = { defaultMessage: 'Computes the distance between two points.\nFor cartesian geometries, this is the pythagorean distance in the same units as the original coordinates.\nFor geographic geometries, this is the circular distance along the great circle in meters.', }), + preview: false, alias: undefined, signatures: [ { @@ -6997,6 +7067,7 @@ const stIntersectsDefinition: FunctionDefinition = { defaultMessage: 'Returns true if two geometries intersect.\nThey intersect if they have any point in common, including their interior points\n(points along lines or within polygons).\nThis is the inverse of the `ST_DISJOINT` function.\nIn mathematical terms: ST_Intersects(A, B) ⇔ A ⋂ B ≠ ∅', }), + preview: false, alias: undefined, signatures: [ { @@ -7136,6 +7207,7 @@ const stWithinDefinition: FunctionDefinition = { defaultMessage: 'Returns whether the first geometry is within the second geometry.\nThis is the inverse of the `ST_CONTAINS` function.', }), + preview: false, alias: undefined, signatures: [ { @@ -7275,6 +7347,7 @@ const stXDefinition: FunctionDefinition = { defaultMessage: 'Extracts the `x` coordinate from the supplied point.\nIf the points is of type `geo_point` this is equivalent to extracting the `longitude` value.', }), + preview: false, alias: undefined, signatures: [ { @@ -7314,6 +7387,7 @@ const stYDefinition: FunctionDefinition = { defaultMessage: 'Extracts the `y` coordinate from the supplied point.\nIf the points is of type `geo_point` this is equivalent to extracting the `latitude` value.', }), + preview: false, alias: undefined, signatures: [ { @@ -7353,6 +7427,7 @@ const startsWithDefinition: FunctionDefinition = { defaultMessage: 'Returns a boolean that indicates whether a keyword string starts with another string.', }), + preview: false, alias: undefined, signatures: [ { @@ -7430,6 +7505,7 @@ const substringDefinition: FunctionDefinition = { defaultMessage: 'Returns a substring of a string, specified by a start position and an optional length.', }), + preview: false, alias: undefined, signatures: [ { @@ -7490,6 +7566,7 @@ const tanDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.tan', { defaultMessage: 'Returns the tangent of an angle.', }), + preview: false, alias: undefined, signatures: [ { @@ -7546,6 +7623,7 @@ const tanhDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.tanh', { defaultMessage: 'Returns the hyperbolic tangent of a number.', }), + preview: false, alias: undefined, signatures: [ { @@ -7602,6 +7680,7 @@ const tauDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.tau', { defaultMessage: "Returns the ratio of a circle's circumference to its radius.", }), + preview: false, alias: undefined, signatures: [ { @@ -7622,6 +7701,7 @@ const toBase64Definition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_base64', { defaultMessage: 'Encode a string to a base64 string.', }), + preview: false, alias: undefined, signatures: [ { @@ -7659,6 +7739,7 @@ const toBooleanDefinition: FunctionDefinition = { defaultMessage: 'Converts an input value to a boolean value.\nA string value of *true* will be case-insensitive converted to the Boolean *true*.\nFor anything else, including the empty string, the function will return *false*.\nThe numerical value of *0* will be converted to *false*, anything else will be converted to *true*.', }), + preview: false, alias: ['to_bool'], signatures: [ { @@ -7749,6 +7830,7 @@ const toCartesianpointDefinition: FunctionDefinition = { 'Converts an input value to a `cartesian_point` value.\nA string will only be successfully converted if it respects WKT Point format.', } ), + preview: false, alias: undefined, signatures: [ { @@ -7801,6 +7883,7 @@ const toCartesianshapeDefinition: FunctionDefinition = { 'Converts an input value to a `cartesian_shape` value.\nA string will only be successfully converted if it respects WKT format.', } ), + preview: false, alias: undefined, signatures: [ { @@ -7859,6 +7942,7 @@ const toDateNanosDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_date_nanos', { defaultMessage: 'Converts an input to a nanosecond-resolution date value (aka date_nanos).', }), + preview: true, alias: undefined, signatures: [], supportedCommands: ['stats', 'inlinestats', 'metrics', 'eval', 'where', 'row', 'sort'], @@ -7874,6 +7958,7 @@ const toDateperiodDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_dateperiod', { defaultMessage: 'Converts an input value into a `date_period` value.', }), + preview: false, alias: undefined, signatures: [ { @@ -7923,6 +8008,7 @@ const toDatetimeDefinition: FunctionDefinition = { defaultMessage: "Converts an input value to a date value.\nA string will only be successfully converted if it's respecting the format `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'`.\nTo convert dates in other formats, use `DATE_PARSE`.", }), + preview: false, alias: ['to_dt'], signatures: [ { @@ -8012,6 +8098,7 @@ const toDegreesDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_degrees', { defaultMessage: 'Converts a number in radians to degrees.', }), + preview: false, alias: undefined, signatures: [ { @@ -8069,6 +8156,7 @@ const toDoubleDefinition: FunctionDefinition = { defaultMessage: 'Converts an input value to a double value. If the input parameter is of a date type,\nits value will be interpreted as milliseconds since the Unix epoch,\nconverted to double. Boolean *true* will be converted to double *1.0*, *false* to *0.0*.', }), + preview: false, alias: ['to_dbl'], signatures: [ { @@ -8198,6 +8286,7 @@ const toGeopointDefinition: FunctionDefinition = { defaultMessage: 'Converts an input value to a `geo_point` value.\nA string will only be successfully converted if it respects WKT Point format.', }), + preview: false, alias: undefined, signatures: [ { @@ -8245,6 +8334,7 @@ const toGeoshapeDefinition: FunctionDefinition = { defaultMessage: 'Converts an input value to a `geo_shape` value.\nA string will only be successfully converted if it respects WKT format.', }), + preview: false, alias: undefined, signatures: [ { @@ -8304,6 +8394,7 @@ const toIntegerDefinition: FunctionDefinition = { defaultMessage: 'Converts an input value to an integer value.\nIf the input parameter is of a date type, its value will be interpreted as milliseconds\nsince the Unix epoch, converted to integer.\nBoolean *true* will be converted to integer *1*, *false* to *0*.', }), + preview: false, alias: ['to_int'], signatures: [ { @@ -8410,6 +8501,7 @@ const toIpDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_ip', { defaultMessage: 'Converts an input string to an IP value.', }), + preview: false, alias: undefined, signatures: [ { @@ -8459,6 +8551,7 @@ const toLongDefinition: FunctionDefinition = { defaultMessage: 'Converts an input value to a long value. If the input parameter is of a date type,\nits value will be interpreted as milliseconds since the Unix epoch, converted to long.\nBoolean *true* will be converted to long *1*, *false* to *0*.', }), + preview: false, alias: undefined, signatures: [ { @@ -8577,6 +8670,7 @@ const toLowerDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_lower', { defaultMessage: 'Returns a new string representing the input string converted to lower case.', }), + preview: false, alias: undefined, signatures: [ { @@ -8613,6 +8707,7 @@ const toRadiansDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_radians', { defaultMessage: 'Converts a number in degrees to radians.', }), + preview: false, alias: undefined, signatures: [ { @@ -8669,6 +8764,7 @@ const toStringDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_string', { defaultMessage: 'Converts an input value into a string.', }), + preview: false, alias: ['to_str'], signatures: [ { @@ -8825,6 +8921,7 @@ const toTimedurationDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_timeduration', { defaultMessage: 'Converts an input value into a `time_duration` value.', }), + preview: false, alias: undefined, signatures: [ { @@ -8877,6 +8974,7 @@ const toUnsignedLongDefinition: FunctionDefinition = { 'Converts an input value to an unsigned long value. If the input parameter is of a date type,\nits value will be interpreted as milliseconds since the Unix epoch, converted to unsigned long.\nBoolean *true* will be converted to unsigned long *1*, *false* to *0*.', } ), + preview: false, alias: ['to_ul', 'to_ulong'], signatures: [ { @@ -8975,6 +9073,7 @@ const toUpperDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_upper', { defaultMessage: 'Returns a new string representing the input string converted to upper case.', }), + preview: false, alias: undefined, signatures: [ { @@ -9011,6 +9110,7 @@ const toVersionDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_version', { defaultMessage: 'Converts an input string to a version value.', }), + preview: false, alias: ['to_ver'], signatures: [ { @@ -9057,6 +9157,7 @@ const trimDefinition: FunctionDefinition = { description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.trim', { defaultMessage: 'Removes leading and trailing whitespaces from a string.', }), + preview: false, alias: undefined, signatures: [ { @@ -9096,6 +9197,7 @@ const caseDefinition: FunctionDefinition = { defaultMessage: 'Accepts pairs of conditions and values. The function returns the value that belongs to the first condition that evaluates to `true`. If the number of arguments is odd, the last argument is the default value which is returned when no condition matches.', }), + preview: false, alias: undefined, signatures: [ { diff --git a/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts b/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts index ff461683d8e7..ba0a50c4a71b 100644 --- a/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts +++ b/packages/kbn-esql-validation-autocomplete/src/definitions/types.ts @@ -7,7 +7,13 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { ESQLCommand, ESQLCommandOption, ESQLFunction, ESQLMessage } from '@kbn/esql-ast'; +import type { + ESQLAstItem, + ESQLCommand, + ESQLCommandOption, + ESQLFunction, + ESQLMessage, +} from '@kbn/esql-ast'; import { GetColumnsByTypeFn, SuggestionRawDefinition } from '../autocomplete/types'; /** @@ -112,6 +118,7 @@ export const isReturnType = (str: string | FunctionParameterType): str is Functi export interface FunctionDefinition { type: 'builtin' | 'agg' | 'eval'; + preview?: boolean; ignoreAsSuggestion?: boolean; name: string; alias?: string[]; @@ -173,6 +180,7 @@ export interface CommandBaseDefinition { getColumnsByType: GetColumnsByTypeFn, columnExists: (column: string) => boolean, getSuggestedVariableName: () => string, + getExpressionType: (expression: ESQLAstItem | undefined) => SupportedDataType | 'unknown', getPreferences?: () => Promise<{ histogramBarTarget: number } | undefined> ) => Promise; /** @deprecated this property will disappear in the future */ diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/context.ts b/packages/kbn-esql-validation-autocomplete/src/shared/context.ts index 42e63d7623e4..cc7c36abf64f 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/context.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/context.ts @@ -26,6 +26,7 @@ import { isSettingItem, pipePrecedesCurrentWord, getFunctionDefinition, + isIdentifier, } from './helpers'; function findNode(nodes: ESQLAstItem[], offset: number): ESQLSingleAstItem | undefined { @@ -87,7 +88,9 @@ function findCommandSubType( function isMarkerNode(node: ESQLSingleAstItem | undefined): boolean { return Boolean( - node && (isColumnItem(node) || isSourceItem(node)) && node.name.endsWith(EDITOR_MARKER) + node && + (isColumnItem(node) || isIdentifier(node) || isSourceItem(node)) && + node.name.endsWith(EDITOR_MARKER) ); } diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.test.ts b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.test.ts index 97f35e1c6672..f880143108ce 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.test.ts @@ -57,6 +57,10 @@ describe('getExpressionType', () => { return root.commands[1].args[0]; }; + test('empty expression', () => { + expect(getExpressionType(getASTForExpression(''))).toBe('unknown'); + }); + describe('literal expressions', () => { const cases: Array<{ expression: string; expectedType: SupportedDataType }> = [ { @@ -289,6 +293,19 @@ describe('getExpressionType', () => { it('supports COUNT(*)', () => { expect(getExpressionType(getASTForExpression('COUNT(*)'))).toBe('long'); }); + + it('accounts for the "any" parameter type', () => { + setTestFunctions([ + { + type: 'eval', + name: 'test', + description: 'Test function', + supportedCommands: ['eval'], + signatures: [{ params: [{ name: 'arg', type: 'any' }], returnType: 'keyword' }], + }, + ]); + expect(getExpressionType(getASTForExpression('test(1)'))).toBe('keyword'); + }); }); describe('lists', () => { diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts index 43bbb2b571a5..2c864a487026 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts @@ -7,18 +7,24 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { - ESQLAstItem, - ESQLColumn, - ESQLCommandMode, - ESQLCommandOption, - ESQLFunction, - ESQLLiteral, - ESQLSingleAstItem, - ESQLSource, - ESQLTimeInterval, +import { + Walker, + type ESQLAstItem, + type ESQLColumn, + type ESQLCommandMode, + type ESQLCommandOption, + type ESQLFunction, + type ESQLLiteral, + type ESQLSingleAstItem, + type ESQLSource, + type ESQLTimeInterval, } from '@kbn/esql-ast'; -import { ESQLInlineCast, ESQLParamLiteral } from '@kbn/esql-ast/src/types'; +import { + ESQLIdentifier, + ESQLInlineCast, + ESQLParamLiteral, + ESQLProperNode, +} from '@kbn/esql-ast/src/types'; import { aggregationFunctionDefinitions } from '../definitions/generated/aggregation_functions'; import { builtinFunctions } from '../definitions/builtin'; import { commandDefinitions } from '../definitions/commands'; @@ -78,6 +84,10 @@ export function isColumnItem(arg: ESQLAstItem): arg is ESQLColumn { return isSingleItem(arg) && arg.type === 'column'; } +export function isIdentifier(arg: ESQLAstItem): arg is ESQLIdentifier { + return isSingleItem(arg) && arg.type === 'identifier'; +} + export function isLiteralItem(arg: ESQLAstItem): arg is ESQLLiteral { return isSingleItem(arg) && arg.type === 'literal'; } @@ -254,10 +264,11 @@ function doesLiteralMatchParameterType(argType: FunctionParameterType, item: ESQ * This function returns the variable or field matching a column */ export function getColumnForASTNode( - column: ESQLColumn, + node: ESQLColumn | ESQLIdentifier, { fields, variables }: Pick ): ESQLRealField | ESQLVariable | undefined { - return getColumnByName(column.parts.join('.'), { fields, variables }); + const formatted = node.type === 'identifier' ? node.name : node.parts.join('.'); + return getColumnByName(formatted, { fields, variables }); } /** @@ -438,7 +449,10 @@ export function checkFunctionArgMatchesDefinition( parentCommand?: string ) { const argType = parameterDefinition.type; - if (argType === 'any' || isParam(arg)) { + if (argType === 'any') { + return true; + } + if (isParam(arg)) { return true; } if (arg.type === 'literal') { @@ -465,7 +479,8 @@ export function checkFunctionArgMatchesDefinition( const wrappedTypes: Array<(typeof validHit)['type']> = Array.isArray(validHit.type) ? validHit.type : [validHit.type]; - return wrappedTypes.some((ct) => ct === argType || ct === 'null'); + + return wrappedTypes.some((ct) => ct === argType || ct === 'null' || ct === 'unknown'); } if (arg.type === 'inlineCast') { const lowerArgType = argType?.toLowerCase(); @@ -543,20 +558,20 @@ export function isVariable( * * E.g. "`bytes`" will be "`bytes`" * - * @param column + * @param node * @returns */ -export const getQuotedColumnName = (column: ESQLColumn) => - column.quoted ? column.text : column.name; +export const getQuotedColumnName = (node: ESQLColumn | ESQLIdentifier) => + node.type === 'identifier' ? node.name : node.quoted ? node.text : node.name; /** * TODO - consider calling lookupColumn under the hood of this function. Seems like they should really do the same thing. */ export function getColumnExists( - column: ESQLColumn, + node: ESQLColumn | ESQLIdentifier, { fields, variables }: Pick ) { - const columnName = column.parts.join('.'); + const columnName = node.type === 'identifier' ? node.name : node.parts.join('.'); if (fields.has(columnName) || variables.has(columnName)) { return true; } @@ -615,6 +630,10 @@ export function findPreviousWord(text: string) { return words[words.length - 2]; } +export function endsInWhitespace(text: string) { + return /\s$/.test(text); +} + /** * Returns the word at the end of the text if there is one. * @param text @@ -645,6 +664,18 @@ export const isParam = (x: unknown): x is ESQLParamLiteral => (x as ESQLParamLiteral).type === 'literal' && (x as ESQLParamLiteral).literalType === 'param'; +export const isFunctionOperatorParam = (fn: ESQLFunction): boolean => + !!fn.operator && isParam(fn.operator); + +/** + * Returns `true` if the function is an aggregation function or a function + * name is a parameter, which potentially could be an aggregation function. + */ +export const isMaybeAggFunction = (fn: ESQLFunction): boolean => + isAggFunction(fn) || isFunctionOperatorParam(fn); + +export const isParametrized = (node: ESQLProperNode): boolean => Walker.params(node).length > 0; + /** * Compares two strings in a case-insensitive manner */ @@ -778,10 +809,14 @@ export function getParamAtPosition( * Determines the type of the expression */ export function getExpressionType( - root: ESQLAstItem, + root: ESQLAstItem | undefined, fields?: Map, variables?: Map ): SupportedDataType | 'unknown' { + if (!root) { + return 'unknown'; + } + if (!isSingleItem(root)) { if (root.length === 0) { return 'unknown'; @@ -878,7 +913,8 @@ export function getExpressionType( const param = getParamAtPosition(signature, i); return ( param && - (param.type === argType || + (param.type === 'any' || + param.type === argType || (argType === 'keyword' && ['date', 'date_period'].includes(param.type))) ); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts index ec0fbe539533..d0d2a1bfec0a 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts @@ -552,11 +552,7 @@ describe('function validation', () => { | EVAL foo = TEST1(1.) | EVAL TEST2(foo) | EVAL TEST3(foo)`, - [ - 'Argument of [test1] must be [keyword], found value [1.] type [double]', - 'Argument of [test2] must be [keyword], found value [foo] type [unknown]', - 'Argument of [test3] must be [long], found value [foo] type [unknown]', - ] + ['Argument of [test1] must be [keyword], found value [1.] type [double]'] ); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.inlinestats.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.inlinestats.ts index c1c7340da78f..a8fa55128251 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.inlinestats.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.inlinestats.ts @@ -126,10 +126,10 @@ export const validationStatsCommandTestSuite = (setup: helpers.Setup) => { const { expectErrors } = await setup(); await expectErrors('from a_index | INLINESTATS doubleField=', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); await expectErrors('from a_index | INLINESTATS doubleField=5 by ', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); await expectErrors('from a_index | INLINESTATS avg(doubleField) by wrongField', [ 'Unknown column [wrongField]', @@ -186,7 +186,7 @@ export const validationStatsCommandTestSuite = (setup: helpers.Setup) => { const { expectErrors } = await setup(); await expectErrors('from a_index | INLINESTATS by ', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.metrics.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.metrics.ts index 79dc4e21fe9d..5384fdc136b4 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.metrics.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.metrics.ts @@ -117,11 +117,11 @@ export const validationMetricsCommandTestSuite = (setup: helpers.Setup) => { await expectErrors('metrics a_index doubleField=', [ expect.any(String), - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); await expectErrors('metrics a_index doubleField=5 by ', [ expect.any(String), - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.stats.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.stats.ts index c499f2477e14..c250166b8896 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.stats.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.stats.ts @@ -117,10 +117,10 @@ export const validationStatsCommandTestSuite = (setup: helpers.Setup) => { const { expectErrors } = await setup(); await expectErrors('from a_index | stats doubleField=', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); await expectErrors('from a_index | stats doubleField=5 by ', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); await expectErrors('from a_index | stats avg(doubleField) by wrongField', [ 'Unknown column [wrongField]', @@ -176,7 +176,7 @@ export const validationStatsCommandTestSuite = (setup: helpers.Setup) => { const { expectErrors } = await setup(); await expectErrors('from a_index | stats by ', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); }); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.params.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.params.test.ts index bbb286798142..e2de846651b0 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.params.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/__tests__/validation.params.test.ts @@ -42,3 +42,168 @@ test('allow params in WHERE command expressions', async () => { expect(res2).toMatchObject({ errors: [], warnings: [] }); expect(res3).toMatchObject({ errors: [], warnings: [] }); }); + +describe('allows named params', () => { + test('WHERE boolean expression can contain a param', async () => { + const { validate } = await setup(); + + const res0 = await validate('FROM index | STATS var = ?func(?field) | WHERE var >= ?value'); + expect(res0).toMatchObject({ errors: [], warnings: [] }); + + const res1 = await validate('FROM index | STATS var = ?param | WHERE var >= ?value'); + expect(res1).toMatchObject({ errors: [], warnings: [] }); + + const res2 = await validate('FROM index | STATS var = ?param | WHERE var >= ?value'); + expect(res2).toMatchObject({ errors: [], warnings: [] }); + + const res3 = await validate('FROM index | STATS var = ?param | WHERE ?value >= var'); + expect(res3).toMatchObject({ errors: [], warnings: [] }); + }); + + test('in column names', async () => { + const { validate } = await setup(); + + const res1 = await validate('ROW ?test'); + expect(res1).toMatchObject({ errors: [], warnings: [] }); + + const res2 = await validate('ROW ?test, ?one_more, ?asldfkjasldkfjasldkfj'); + expect(res2).toMatchObject({ errors: [], warnings: [] }); + }); + + test('in nested column names', async () => { + const { validate } = await setup(); + + const res1 = await validate('ROW ?test.?test2'); + expect(res1).toMatchObject({ errors: [], warnings: [] }); + + const res2 = await validate('ROW ?test, ?test.?test2.?test3'); + expect(res2).toMatchObject({ errors: [], warnings: [] }); + }); + + test('in nested column names, where first part is not a param', async () => { + const { validate } = await setup(); + + const res1 = await validate('ROW not_a_param.?test2'); + expect(res1).toMatchObject({ errors: [], warnings: [] }); + + const res2 = await validate('ROW not_a_param.?asdfasdfasdf, not_a_param.?test2.?test3'); + expect(res2).toMatchObject({ errors: [], warnings: [] }); + }); + + test('in function name, function arg, and column name in STATS command', async () => { + const { validate } = await setup(); + + const res1 = await validate('FROM index | STATS x = max(doubleField) BY textField'); + expect(res1).toMatchObject({ errors: [], warnings: [] }); + + const res2 = await validate('FROM index | STATS x = max(?param1) BY textField'); + expect(res2).toMatchObject({ errors: [], warnings: [] }); + + const res3 = await validate('FROM index | STATS x = max(?param1) BY ?param2'); + expect(res3).toMatchObject({ errors: [], warnings: [] }); + + const res4 = await validate('FROM index | STATS x = ?param3(?param1) BY ?param2'); + expect(res4).toMatchObject({ errors: [], warnings: [] }); + + const res5 = await validate( + 'FROM index | STATS x = ?param3(?param1, ?param4), y = ?param4(?param4, ?param4, ?param4) BY ?param2, ?param5' + ); + expect(res5).toMatchObject({ errors: [], warnings: [] }); + }); +}); + +describe('allows unnamed params', () => { + test('in column names', async () => { + const { validate } = await setup(); + + const res1 = await validate('ROW ?'); + expect(res1).toMatchObject({ errors: [], warnings: [] }); + }); + + test('in nested column names', async () => { + const { validate } = await setup(); + + const res1 = await validate('ROW ?.?'); + expect(res1).toMatchObject({ errors: [], warnings: [] }); + + const res2 = await validate('ROW ?, ?.?.?'); + expect(res2).toMatchObject({ errors: [], warnings: [] }); + }); + + test('in nested column names, where first part is not a param', async () => { + const { validate } = await setup(); + + const res1 = await validate('ROW not_a_param.?'); + expect(res1).toMatchObject({ errors: [], warnings: [] }); + + const res2 = await validate('ROW not_a_param.?, not_a_param.?.?'); + expect(res2).toMatchObject({ errors: [], warnings: [] }); + }); + + test('in function name, function arg, and column name in STATS command', async () => { + const { validate } = await setup(); + + const res1 = await validate('FROM index | STATS x = max(doubleField) BY textField'); + expect(res1).toMatchObject({ errors: [], warnings: [] }); + + const res2 = await validate('FROM index | STATS x = max(?) BY textField'); + expect(res2).toMatchObject({ errors: [], warnings: [] }); + + const res3 = await validate('FROM index | STATS x = max(?) BY ?'); + expect(res3).toMatchObject({ errors: [], warnings: [] }); + + const res4 = await validate('FROM index | STATS x = ?(?) BY ?'); + expect(res4).toMatchObject({ errors: [], warnings: [] }); + + const res5 = await validate('FROM index | STATS x = ?(?, ?), y = ?(?, ?, ?) BY ?, ?'); + expect(res5).toMatchObject({ errors: [], warnings: [] }); + }); +}); + +describe('allows positional params', () => { + test('in column names', async () => { + const { validate } = await setup(); + + const res1 = await validate('ROW ?0'); + expect(res1).toMatchObject({ errors: [], warnings: [] }); + }); + + test('in nested column names', async () => { + const { validate } = await setup(); + + const res1 = await validate('ROW ?0.?0'); + expect(res1).toMatchObject({ errors: [], warnings: [] }); + + const res2 = await validate('ROW ?0, ?0.?0.?0'); + expect(res2).toMatchObject({ errors: [], warnings: [] }); + }); + + test('in nested column names, where first part is not a param', async () => { + const { validate } = await setup(); + + const res1 = await validate('ROW not_a_param.?1'); + expect(res1).toMatchObject({ errors: [], warnings: [] }); + + const res2 = await validate('ROW not_a_param.?2, not_a_param.?3.?4'); + expect(res2).toMatchObject({ errors: [], warnings: [] }); + }); + + test('in function name, function arg, and column name in STATS command', async () => { + const { validate } = await setup(); + + const res1 = await validate('FROM index | STATS x = max(doubleField) BY textField'); + expect(res1).toMatchObject({ errors: [], warnings: [] }); + + const res2 = await validate('FROM index | STATS x = max(?0) BY textField'); + expect(res2).toMatchObject({ errors: [], warnings: [] }); + + const res3 = await validate('FROM index | STATS x = max(?0) BY ?0'); + expect(res3).toMatchObject({ errors: [], warnings: [] }); + + const res4 = await validate('FROM index | STATS x = ?1(?1) BY ?1'); + expect(res4).toMatchObject({ errors: [], warnings: [] }); + + const res5 = await validate('FROM index | STATS x = ?0(?0, ?0), y = ?2(?2, ?2, ?2) BY ?3, ?3'); + expect(res5).toMatchObject({ errors: [], warnings: [] }); + }); +}); diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/errors.ts b/packages/kbn-esql-validation-autocomplete/src/validation/errors.ts index ae00f300c187..0f82d7fe4aad 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/errors.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/errors.ts @@ -15,6 +15,7 @@ import type { ESQLLocation, ESQLMessage, } from '@kbn/esql-ast'; +import { ESQLIdentifier } from '@kbn/esql-ast/src/types'; import type { ErrorTypes, ErrorValues } from './types'; function getMessageAndTypeFromId({ @@ -477,7 +478,7 @@ export const errors = { unknownFunction: (fn: ESQLFunction): ESQLMessage => errors.byId('unknownFunction', fn.location, fn), - unknownColumn: (column: ESQLColumn): ESQLMessage => + unknownColumn: (column: ESQLColumn | ESQLIdentifier): ESQLMessage => errors.byId('unknownColumn', column.location, { name: column.name, }), @@ -494,9 +495,12 @@ export const errors = { expression: fn.text, }), - unknownAggFunction: (col: ESQLColumn, type: string = 'FieldAttribute'): ESQLMessage => - errors.byId('unknownAggregateFunction', col.location, { - value: col.name, + unknownAggFunction: ( + node: ESQLColumn | ESQLIdentifier, + type: string = 'FieldAttribute' + ): ESQLMessage => + errors.byId('unknownAggregateFunction', node.location, { + value: node.name, type, }), diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json b/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json index 25fb880da5ff..bf0e9782a339 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json +++ b/packages/kbn-esql-validation-autocomplete/src/validation/esql_validation_meta_tests.json @@ -223,7 +223,7 @@ { "query": "row", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, @@ -331,7 +331,7 @@ { "query": "row var = 1 in (", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", "Error: [in] function expects exactly 2 arguments, got 1." ], "warning": [] @@ -2645,7 +2645,7 @@ { "query": "from a_index | dissect", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, @@ -2666,8 +2666,7 @@ { "query": "from a_index | dissect textField .", "error": [ - "SyntaxError: mismatched input '' expecting {'?', NAMED_OR_POSITIONAL_PARAM, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", - "Unknown column [textField.]" + "SyntaxError: mismatched input '' expecting {'?', NAMED_OR_POSITIONAL_PARAM, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, @@ -2740,7 +2739,7 @@ { "query": "from a_index | grok", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, @@ -2761,8 +2760,7 @@ { "query": "from a_index | grok textField .", "error": [ - "SyntaxError: mismatched input '' expecting {'?', NAMED_OR_POSITIONAL_PARAM, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", - "Unknown column [textField.]" + "SyntaxError: mismatched input '' expecting {'?', NAMED_OR_POSITIONAL_PARAM, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, @@ -3542,21 +3540,21 @@ { "query": "from a_index | where *+ doubleField", "error": [ - "SyntaxError: extraneous input '*' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: extraneous input '*' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, { "query": "from a_index | where /+ doubleField", "error": [ - "SyntaxError: extraneous input '/' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: extraneous input '/' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, { "query": "from a_index | where %+ doubleField", "error": [ - "SyntaxError: extraneous input '%' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: extraneous input '%' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, @@ -4443,7 +4441,7 @@ { "query": "from a_index | eval ", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, @@ -4486,7 +4484,7 @@ { "query": "from a_index | eval a=b, ", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", "Unknown column [b]" ], "warning": [] @@ -4513,7 +4511,7 @@ { "query": "from a_index | eval a=round(doubleField), ", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, @@ -5619,21 +5617,21 @@ { "query": "from a_index | eval *+ doubleField", "error": [ - "SyntaxError: extraneous input '*' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: extraneous input '*' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, { "query": "from a_index | eval /+ doubleField", "error": [ - "SyntaxError: extraneous input '/' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: extraneous input '/' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, { "query": "from a_index | eval %+ doubleField", "error": [ - "SyntaxError: extraneous input '%' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: extraneous input '%' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, @@ -6957,7 +6955,7 @@ { "query": "from a_index | eval not", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", "Error: [not] function expects exactly one argument, got 0." ], "warning": [] @@ -6965,7 +6963,7 @@ { "query": "from a_index | eval in", "error": [ - "SyntaxError: mismatched input 'in' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: mismatched input 'in' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, @@ -9014,7 +9012,7 @@ { "query": "from a_index | sort ", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, @@ -9033,7 +9031,7 @@ { "query": "from a_index | sort doubleField, ", "error": [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}" ], "warning": [] }, @@ -9955,11 +9953,11 @@ "warning": [] }, { - "query": "from index METADATA _id, _source METADATA _id2", + "query": "from index metadata _id, _source METADATA _id2", "error": [ "SyntaxError: mismatched input 'METADATA' expecting " ], "warning": [] } ] -} +} \ No newline at end of file diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts index e6546ec99654..9d737d542bd1 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts @@ -306,7 +306,7 @@ describe('validation logic', () => { describe('row', () => { testErrorsAndWarnings('row', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); testErrorsAndWarnings('row missing_column', ['Unknown column [missing_column]']); testErrorsAndWarnings('row fn()', ['Unknown function [fn]']); @@ -335,7 +335,7 @@ describe('validation logic', () => { "SyntaxError: mismatched input '' expecting '('", ]); testErrorsAndWarnings('row var = 1 in (', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", 'Error: [in] function expects exactly 2 arguments, got 1.', ]); testErrorsAndWarnings('row var = 1 not in ', [ @@ -690,7 +690,7 @@ describe('validation logic', () => { describe('dissect', () => { testErrorsAndWarnings('from a_index | dissect', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); testErrorsAndWarnings('from a_index | dissect textField', [ "SyntaxError: missing QUOTED_STRING at ''", @@ -700,7 +700,6 @@ describe('validation logic', () => { ]); testErrorsAndWarnings('from a_index | dissect textField .', [ "SyntaxError: mismatched input '' expecting {'?', NAMED_OR_POSITIONAL_PARAM, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", - 'Unknown column [textField.]', ]); testErrorsAndWarnings('from a_index | dissect textField %a', [ "SyntaxError: mismatched input '%' expecting QUOTED_STRING", @@ -741,7 +740,7 @@ describe('validation logic', () => { describe('grok', () => { testErrorsAndWarnings('from a_index | grok', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); testErrorsAndWarnings('from a_index | grok textField', [ "SyntaxError: missing QUOTED_STRING at ''", @@ -751,7 +750,6 @@ describe('validation logic', () => { ]); testErrorsAndWarnings('from a_index | grok textField .', [ "SyntaxError: mismatched input '' expecting {'?', NAMED_OR_POSITIONAL_PARAM, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", - 'Unknown column [textField.]', ]); testErrorsAndWarnings('from a_index | grok textField %a', [ "SyntaxError: mismatched input '%' expecting QUOTED_STRING", @@ -826,7 +824,7 @@ describe('validation logic', () => { } for (const wrongOp of ['*', '/', '%']) { testErrorsAndWarnings(`from a_index | where ${wrongOp}+ doubleField`, [ - `SyntaxError: extraneous input '${wrongOp}' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}`, + `SyntaxError: extraneous input '${wrongOp}' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}`, ]); } @@ -899,7 +897,7 @@ describe('validation logic', () => { describe('eval', () => { testErrorsAndWarnings('from a_index | eval ', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); testErrorsAndWarnings('from a_index | eval textField ', []); testErrorsAndWarnings('from a_index | eval b = textField', []); @@ -912,7 +910,7 @@ describe('validation logic', () => { ]); testErrorsAndWarnings('from a_index | eval a=b', ['Unknown column [b]']); testErrorsAndWarnings('from a_index | eval a=b, ', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", 'Unknown column [b]', ]); testErrorsAndWarnings('from a_index | eval a=round', ['Unknown column [round]']); @@ -921,7 +919,7 @@ describe('validation logic', () => { ]); testErrorsAndWarnings('from a_index | eval a=round(doubleField) ', []); testErrorsAndWarnings('from a_index | eval a=round(doubleField), ', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); testErrorsAndWarnings('from a_index | eval a=round(doubleField) + round(doubleField) ', []); testErrorsAndWarnings('from a_index | eval a=round(doubleField) + round(textField) ', [ @@ -984,7 +982,7 @@ describe('validation logic', () => { for (const wrongOp of ['*', '/', '%']) { testErrorsAndWarnings(`from a_index | eval ${wrongOp}+ doubleField`, [ - `SyntaxError: extraneous input '${wrongOp}' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}`, + `SyntaxError: extraneous input '${wrongOp}' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}`, ]); } testErrorsAndWarnings( @@ -1203,11 +1201,11 @@ describe('validation logic', () => { [] ); testErrorsAndWarnings('from a_index | eval not', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", 'Error: [not] function expects exactly one argument, got 0.', ]); testErrorsAndWarnings('from a_index | eval in', [ - "SyntaxError: mismatched input 'in' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input 'in' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); testErrorsAndWarnings('from a_index | eval textField in textField', [ @@ -1289,12 +1287,12 @@ describe('validation logic', () => { describe('sort', () => { testErrorsAndWarnings('from a_index | sort ', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); testErrorsAndWarnings('from a_index | sort "field" ', []); testErrorsAndWarnings('from a_index | sort wrongField ', ['Unknown column [wrongField]']); testErrorsAndWarnings('from a_index | sort doubleField, ', [ - "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', 'match', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", + "SyntaxError: mismatched input '' expecting {QUOTED_STRING, INTEGER_LITERAL, DECIMAL_LITERAL, 'false', '(', 'not', 'null', '?', 'true', '+', '-', NAMED_OR_POSITIONAL_PARAM, OPENING_BRACKET, UNQUOTED_IDENTIFIER, QUOTED_IDENTIFIER}", ]); testErrorsAndWarnings('from a_index | sort doubleField, textField', []); for (const dir of ['desc', 'asc']) { diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts index 111fe79b3f5e..b43a9e5c336b 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts @@ -21,7 +21,7 @@ import { ESQLSource, walk, } from '@kbn/esql-ast'; -import type { ESQLAstField } from '@kbn/esql-ast/src/types'; +import type { ESQLAstField, ESQLIdentifier } from '@kbn/esql-ast/src/types'; import { CommandModeDefinition, CommandOptionsDefinition, @@ -54,6 +54,10 @@ import { getQuotedColumnName, isInlineCastItem, getSignaturesWithMatchingArity, + isIdentifier, + isFunctionOperatorParam, + isMaybeAggFunction, + isParametrized, } from '../shared/helpers'; import { collectVariables } from '../shared/variables'; import { getMessageFromId, errors } from './errors'; @@ -235,7 +239,7 @@ function validateFunctionColumnArg( parentCommand: string ) { const messages: ESQLMessage[] = []; - if (!isColumnItem(actualArg)) { + if (!(isColumnItem(actualArg) || isIdentifier(actualArg))) { return messages; } @@ -317,7 +321,7 @@ function removeInlineCasts(arg: ESQLAstItem): ESQLAstItem { } function validateFunction( - astFunction: ESQLFunction, + fn: ESQLFunction, parentCommand: string, parentOption: string | undefined, references: ReferenceMaps, @@ -326,16 +330,20 @@ function validateFunction( ): ESQLMessage[] { const messages: ESQLMessage[] = []; - if (astFunction.incomplete) { + if (fn.incomplete) { return messages; } - const fnDefinition = getFunctionDefinition(astFunction.name)!; - const isFnSupported = isSupportedFunction(astFunction.name, parentCommand, parentOption); + if (isFunctionOperatorParam(fn)) { + return messages; + } + + const fnDefinition = getFunctionDefinition(fn.name)!; + const isFnSupported = isSupportedFunction(fn.name, parentCommand, parentOption); if (!isFnSupported.supported) { if (isFnSupported.reason === 'unknownFunction') { - messages.push(errors.unknownFunction(astFunction)); + messages.push(errors.unknownFunction(fn)); } // for nested functions skip this check and make the nested check fail later on if (isFnSupported.reason === 'unsupportedFunction' && !isNested) { @@ -344,16 +352,16 @@ function validateFunction( ? getMessageFromId({ messageId: 'unsupportedFunctionForCommandOption', values: { - name: astFunction.name, + name: fn.name, command: parentCommand.toUpperCase(), option: parentOption.toUpperCase(), }, - locations: astFunction.location, + locations: fn.location, }) : getMessageFromId({ messageId: 'unsupportedFunctionForCommand', - values: { name: astFunction.name, command: parentCommand.toUpperCase() }, - locations: astFunction.location, + values: { name: fn.name, command: parentCommand.toUpperCase() }, + locations: fn.location, }) ); } @@ -361,7 +369,7 @@ function validateFunction( return messages; } } - const matchingSignatures = getSignaturesWithMatchingArity(fnDefinition, astFunction); + const matchingSignatures = getSignaturesWithMatchingArity(fnDefinition, fn); if (!matchingSignatures.length) { const { max, min } = getMaxMinNumberOfParams(fnDefinition); if (max === min) { @@ -369,24 +377,24 @@ function validateFunction( getMessageFromId({ messageId: 'wrongArgumentNumber', values: { - fn: astFunction.name, + fn: fn.name, numArgs: max, - passedArgs: astFunction.args.length, + passedArgs: fn.args.length, }, - locations: astFunction.location, + locations: fn.location, }) ); - } else if (astFunction.args.length > max) { + } else if (fn.args.length > max) { messages.push( getMessageFromId({ messageId: 'wrongArgumentNumberTooMany', values: { - fn: astFunction.name, + fn: fn.name, numArgs: max, - passedArgs: astFunction.args.length, - extraArgs: astFunction.args.length - max, + passedArgs: fn.args.length, + extraArgs: fn.args.length - max, }, - locations: astFunction.location, + locations: fn.location, }) ); } else { @@ -394,19 +402,19 @@ function validateFunction( getMessageFromId({ messageId: 'wrongArgumentNumberTooFew', values: { - fn: astFunction.name, + fn: fn.name, numArgs: min, - passedArgs: astFunction.args.length, - missingArgs: min - astFunction.args.length, + passedArgs: fn.args.length, + missingArgs: min - fn.args.length, }, - locations: astFunction.location, + locations: fn.location, }) ); } } // now perform the same check on all functions args - for (let i = 0; i < astFunction.args.length; i++) { - const arg = astFunction.args[i]; + for (let i = 0; i < fn.args.length; i++) { + const arg = fn.args[i]; const allMatchingArgDefinitionsAreConstantOnly = matchingSignatures.every((signature) => { return signature.params[i]?.constantOnly; @@ -446,7 +454,7 @@ function validateFunction( // use the nesting flag for now just for stats and metrics // TODO: revisit this part later on to make it more generic ['stats', 'inlinestats', 'metrics'].includes(parentCommand) - ? isNested || !isAssignment(astFunction) + ? isNested || !isAssignment(fn) : false ); @@ -454,7 +462,7 @@ function validateFunction( const consolidatedMessage = getMessageFromId({ messageId: 'expectedConstant', values: { - fn: astFunction.name, + fn: fn.name, given: subArg.text, }, locations: subArg.location, @@ -472,7 +480,7 @@ function validateFunction( } // check if the definition has some specific validation to apply: if (fnDefinition.validate) { - const payloads = fnDefinition.validate(astFunction); + const payloads = fnDefinition.validate(fn); if (payloads.length) { messages.push(...payloads); } @@ -481,7 +489,7 @@ function validateFunction( const failingSignatures: ESQLMessage[][] = []; for (const signature of matchingSignatures) { const failingSignature: ESQLMessage[] = []; - astFunction.args.forEach((outerArg, index) => { + fn.args.forEach((outerArg, index) => { const argDef = getParamAtPosition(signature, index); if ((!outerArg && argDef?.optional) || !argDef) { // that's ok, just skip it @@ -502,7 +510,7 @@ function validateFunction( validateInlineCastArg, ].flatMap((validateFn) => { return validateFn( - astFunction, + fn, arg, { ...argDef, @@ -521,7 +529,7 @@ function validateFunction( ? collapseWrongArgumentTypeMessages( messagesFromAllArgElements, outerArg, - astFunction.name, + fn.name, argDef.type as string, parentCommand, references @@ -599,10 +607,11 @@ function validateSetting( * recursively terminate at either a literal or an aggregate function. */ const isFunctionAggClosed = (fn: ESQLFunction): boolean => - isAggFunction(fn) || areFunctionArgsAggClosed(fn); + isMaybeAggFunction(fn) || areFunctionArgsAggClosed(fn); const areFunctionArgsAggClosed = (fn: ESQLFunction): boolean => - fn.args.every((arg) => isLiteralItem(arg) || (isFunctionItem(arg) && isFunctionAggClosed(arg))); + fn.args.every((arg) => isLiteralItem(arg) || (isFunctionItem(arg) && isFunctionAggClosed(arg))) || + isFunctionOperatorParam(fn); /** * Looks for first nested aggregate function in an aggregate function, recursively. @@ -610,7 +619,7 @@ const areFunctionArgsAggClosed = (fn: ESQLFunction): boolean => const findNestedAggFunctionInAggFunction = (agg: ESQLFunction): ESQLFunction | undefined => { for (const arg of agg.args) { if (isFunctionItem(arg)) { - return isAggFunction(arg) ? arg : findNestedAggFunctionInAggFunction(arg); + return isMaybeAggFunction(arg) ? arg : findNestedAggFunctionInAggFunction(arg); } } }; @@ -627,7 +636,7 @@ const findNestedAggFunction = ( fn: ESQLFunction, parentIsAgg: boolean = false ): ESQLFunction | undefined => { - if (isAggFunction(fn)) { + if (isMaybeAggFunction(fn)) { return parentIsAgg ? fn : findNestedAggFunctionInAggFunction(fn); } @@ -675,7 +684,7 @@ const validateAggregates = ( hasMissingAggregationFunctionError = true; messages.push(errors.noAggFunction(command, aggregate)); } - } else if (isColumnItem(aggregate)) { + } else if (isColumnItem(aggregate) || isIdentifier(aggregate)) { messages.push(errors.unknownAggFunction(aggregate)); } else { // Should never happen. @@ -834,14 +843,13 @@ function validateSource( } function validateColumnForCommand( - column: ESQLColumn, + column: ESQLColumn | ESQLIdentifier, commandName: string, references: ReferenceMaps ): ESQLMessage[] { const messages: ESQLMessage[] = []; - if (commandName === 'row') { - if (!references.variables.has(column.name)) { + if (!references.variables.has(column.name) && !isParametrized(column)) { messages.push(errors.unknownColumn(column)); } } else { @@ -990,7 +998,7 @@ function validateCommand(command: ESQLCommand, references: ReferenceMaps): ESQLM ) ); } - if (isColumnItem(arg)) { + if (isColumnItem(arg) || isIdentifier(arg)) { if (command.name === 'stats' || command.name === 'inlinestats') { messages.push(errors.unknownAggFunction(arg)); } else { diff --git a/packages/kbn-failed-test-reporter-cli/failed_tests_reporter/failed_tests_reporter_cli.ts b/packages/kbn-failed-test-reporter-cli/failed_tests_reporter/failed_tests_reporter_cli.ts index d86f7f521312..36466c3e3637 100644 --- a/packages/kbn-failed-test-reporter-cli/failed_tests_reporter/failed_tests_reporter_cli.ts +++ b/packages/kbn-failed-test-reporter-cli/failed_tests_reporter/failed_tests_reporter_cli.ts @@ -44,6 +44,7 @@ run( let branch: string = ''; let pipeline: string = ''; + let prependTitle: string = ''; if (updateGithub) { let isPr = false; @@ -52,6 +53,7 @@ run( pipeline = process.env.BUILDKITE_PIPELINE_SLUG || ''; isPr = process.env.BUILDKITE_PULL_REQUEST === 'true'; updateGithub = process.env.REPORT_FAILED_TESTS_TO_GITHUB === 'true'; + prependTitle = process.env.PREPEND_FAILURE_TITLE || ''; } else { // JOB_NAME is formatted as `elastic+kibana+7.x` in some places and `elastic+kibana+7.x/JOB=kibana-intake,node=immutable` in others const jobNameSplit = (process.env.JOB_NAME || '').split(/\+|\//); @@ -154,7 +156,14 @@ run( continue; } - const newIssue = await createFailureIssue(buildUrl, failure, githubApi, branch, pipeline); + const newIssue = await createFailureIssue( + buildUrl, + failure, + githubApi, + branch, + pipeline, + prependTitle + ); existingIssues.addNewlyCreated(failure, newIssue); pushMessage('Test has not failed recently on tracked branches'); if (updateGithub) { diff --git a/packages/kbn-failed-test-reporter-cli/failed_tests_reporter/report_failure.test.ts b/packages/kbn-failed-test-reporter-cli/failed_tests_reporter/report_failure.test.ts index dce47461377c..c7dbd2db7731 100644 --- a/packages/kbn-failed-test-reporter-cli/failed_tests_reporter/report_failure.test.ts +++ b/packages/kbn-failed-test-reporter-cli/failed_tests_reporter/report_failure.test.ts @@ -60,6 +60,53 @@ describe('createFailureIssue()', () => { } `); }); + + it('creates new github issue with title prepended', async () => { + const api = new GithubApi(); + + await createFailureIssue( + 'https://build-url', + { + classname: 'some.classname', + failure: 'this is the failure text', + name: 'test name', + time: '2018-01-01T01:00:00Z', + likelyIrrelevant: false, + }, + api, + 'main', + 'kibana-on-merge', + '[MKI][QA]' + ); + + expect(api.createIssue).toMatchInlineSnapshot(` + [MockFunction] { + "calls": Array [ + Array [ + "Failing test: [MKI][QA] some.classname - test name", + "A test failed on a tracked branch + + \`\`\` + this is the failure text + \`\`\` + + First failure: [kibana-on-merge - main](https://build-url) + + ", + Array [ + "failed-test", + ], + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + } + `); + }); }); describe('updateFailureIssue()', () => { diff --git a/packages/kbn-failed-test-reporter-cli/failed_tests_reporter/report_failure.ts b/packages/kbn-failed-test-reporter-cli/failed_tests_reporter/report_failure.ts index 182bde666c25..d941f94b6b24 100644 --- a/packages/kbn-failed-test-reporter-cli/failed_tests_reporter/report_failure.ts +++ b/packages/kbn-failed-test-reporter-cli/failed_tests_reporter/report_failure.ts @@ -17,9 +17,15 @@ export async function createFailureIssue( failure: TestFailure, api: GithubApi, branch: string, - pipeline: string + pipeline: string, + prependTitle: string = '' ) { - const title = `Failing test: ${failure.classname} - ${failure.name}`; + // PrependTitle is introduced to provide some clarity by prepending the failing test title + // in order to give the whole info in the title according to each team's preference. + const title = + prependTitle && prependTitle.trim() !== '' + ? `Failing test: ${prependTitle} ${failure.classname} - ${failure.name}` + : `Failing test: ${failure.classname} - ${failure.name}`; // Github API body length maximum is 65536 characters // Let's keep consistency with Mocha output that is truncated to 8192 characters diff --git a/packages/kbn-field-utils/index.ts b/packages/kbn-field-utils/index.ts index ae77f0d1524f..d3ce774177dc 100644 --- a/packages/kbn-field-utils/index.ts +++ b/packages/kbn-field-utils/index.ts @@ -25,6 +25,7 @@ export { comboBoxFieldOptionMatcher, getFieldSearchMatchingHighlight, } from './src/utils/field_name_wildcard_matcher'; +export { fieldSupportsBreakdown } from './src/utils/field_supports_breakdown'; export { FieldIcon, type FieldIconProps, getFieldIconProps } from './src/components/field_icon'; export { FieldDescription, type FieldDescriptionProps } from './src/components/field_description'; diff --git a/src/plugins/unified_histogram/public/utils/field_supports_breakdown.test.ts b/packages/kbn-field-utils/src/utils/field_supports_breakdown.test.ts similarity index 100% rename from src/plugins/unified_histogram/public/utils/field_supports_breakdown.test.ts rename to packages/kbn-field-utils/src/utils/field_supports_breakdown.test.ts diff --git a/src/plugins/unified_histogram/public/utils/field_supports_breakdown.ts b/packages/kbn-field-utils/src/utils/field_supports_breakdown.ts similarity index 65% rename from src/plugins/unified_histogram/public/utils/field_supports_breakdown.ts rename to packages/kbn-field-utils/src/utils/field_supports_breakdown.ts index 12fdfbf20aa3..3177d40012b5 100644 --- a/src/plugins/unified_histogram/public/utils/field_supports_breakdown.ts +++ b/packages/kbn-field-utils/src/utils/field_supports_breakdown.ts @@ -7,12 +7,18 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { DataViewField } from '@kbn/data-views-plugin/public'; +import { type DataViewField } from '@kbn/data-views-plugin/common'; +import { KNOWN_FIELD_TYPES } from './field_types'; -const supportedTypes = new Set(['string', 'boolean', 'number', 'ip']); +const supportedTypes = new Set([ + KNOWN_FIELD_TYPES.STRING, + KNOWN_FIELD_TYPES.BOOLEAN, + KNOWN_FIELD_TYPES.NUMBER, + KNOWN_FIELD_TYPES.IP, +]); export const fieldSupportsBreakdown = (field: DataViewField) => - supportedTypes.has(field.type) && + supportedTypes.has(field.type as KNOWN_FIELD_TYPES) && field.aggregatable && !field.scripted && field.timeSeriesMetric !== 'counter'; diff --git a/packages/kbn-ftr-common-functional-services/index.ts b/packages/kbn-ftr-common-functional-services/index.ts index a975c175c583..10ded3da0d35 100644 --- a/packages/kbn-ftr-common-functional-services/index.ts +++ b/packages/kbn-ftr-common-functional-services/index.ts @@ -39,7 +39,7 @@ export type SamlAuthProviderType = ProvidedType; export type { FtrProviderContext } from './services/ftr_provider_context'; export { runSavedObjInfoSvc } from './services/saved_object_info'; -export type { BsearchService, SendOptions } from './services/bsearch'; +export type { SearchService, SendOptions } from './services/search'; export { SavedObjectInfoService } from './services/saved_object_info'; export { DeploymentService } from './services/deployment'; export { IndexPatternsService } from './services/index_patterns'; diff --git a/packages/kbn-ftr-common-functional-services/services/all.ts b/packages/kbn-ftr-common-functional-services/services/all.ts index 2caec10c10eb..dd11b2b914b0 100644 --- a/packages/kbn-ftr-common-functional-services/services/all.ts +++ b/packages/kbn-ftr-common-functional-services/services/all.ts @@ -11,7 +11,7 @@ import { EsArchiverProvider } from './es_archiver'; import { EsProvider } from './es'; import { KibanaServerProvider } from './kibana_server'; import { RetryService } from './retry'; -import { BsearchService } from './bsearch'; +import { SearchService } from './search'; import { ConsoleProvider } from './console'; import { DeploymentService } from './deployment'; import { EsDeleteAllIndicesProvider } from './es_delete_all_indices'; @@ -27,7 +27,7 @@ export const services = { kibanaServer: KibanaServerProvider, esArchiver: EsArchiverProvider, retry: RetryService, - bsearch: BsearchService, + search: SearchService, console: ConsoleProvider, deployment: DeploymentService, esDeleteAllIndices: EsDeleteAllIndicesProvider, diff --git a/packages/kbn-ftr-common-functional-services/services/bsearch.ts b/packages/kbn-ftr-common-functional-services/services/search.ts similarity index 63% rename from packages/kbn-ftr-common-functional-services/services/bsearch.ts rename to packages/kbn-ftr-common-functional-services/services/search.ts index 0fc39cb87cd8..2c9e0f558a36 100644 --- a/packages/kbn-ftr-common-functional-services/services/bsearch.ts +++ b/packages/kbn-ftr-common-functional-services/services/search.ts @@ -8,26 +8,11 @@ */ import expect from '@kbn/expect'; -import request from 'superagent'; import type SuperTest from 'supertest'; import type { IEsSearchResponse } from '@kbn/search-types'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { BFETCH_ROUTE_VERSION_LATEST } from '@kbn/bfetch-plugin/common'; import { FtrService } from './ftr_provider_context'; -/** - * Function copied from here: - * test/api_integration/apis/search/bsearch.ts without the compress - * - * Splits the JSON lines from bsearch - */ -const parseBfetchResponse = (resp: request.Response): Array> => { - return resp.text - .trim() - .split('\n') - .map((item) => JSON.parse(item)); -}; - /** * Function copied from here: * x-pack/test/rule_registry/common/lib/authentication/spaces.ts @@ -48,13 +33,13 @@ export interface SendOptions { } /** - * Bsearch Service that can reduce flake on the CI systems when they are under - * pressure and bsearch returns an async search response or a sync response. + * Search Service that can reduce flake on the CI systems when they are under + * pressure and search returns an async search response or a sync response. * * @example * const supertest = getService('supertest'); - * const bsearch = getService('bsearch'); - * const response = await bsearch.send({ + * const search = getService('search'); + * const response = await search.send({ * supertest, * options: { * defaultIndex: ['large_volume_dns_data'], @@ -64,7 +49,7 @@ export interface SendOptions { * expect(response).eql({ ... your value ... }); */ -export class BsearchService extends FtrService { +export class SearchService extends FtrService { private readonly retry = this.ctx.getService('retry'); /** Send method to send in your supertest, url, options, and strategy name */ @@ -85,26 +70,13 @@ export class BsearchService extends FtrService { const result = await this.retry.try(async () => { const resp = await supertest - .post(`${spaceUrl}/internal/bsearch`) + .post(`${spaceUrl}/internal/search/${strategy}/${body.id}`) .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, BFETCH_ROUTE_VERSION_LATEST) - .send({ - batch: [ - { - request: { - id: body.id, - ...options, - }, - options: { - strategy, - }, - }, - ], - }) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .send(options) .expect(200); - const [parsedResponse] = parseBfetchResponse(resp); - expect(parsedResponse.result.isRunning).equal(false); - return parsedResponse.result as T; + expect(resp.body.isRunning).equal(false); + return resp.body as T; }); return result; } diff --git a/packages/kbn-ftr-common-functional-services/tsconfig.json b/packages/kbn-ftr-common-functional-services/tsconfig.json index 2cad85eb14fb..e5239f467ba4 100644 --- a/packages/kbn-ftr-common-functional-services/tsconfig.json +++ b/packages/kbn-ftr-common-functional-services/tsconfig.json @@ -19,7 +19,6 @@ "@kbn/expect", "@kbn/search-types", "@kbn/core-http-common", - "@kbn/bfetch-plugin", "@kbn/data-plugin", "@kbn/dev-cli-runner", "@kbn/dev-cli-errors", diff --git a/packages/kbn-kibana-manifest-schema/src/kibana_json_v2_schema.ts b/packages/kbn-kibana-manifest-schema/src/kibana_json_v2_schema.ts index 30682d763e0b..a243dbb7598c 100644 --- a/packages/kbn-kibana-manifest-schema/src/kibana_json_v2_schema.ts +++ b/packages/kbn-kibana-manifest-schema/src/kibana_json_v2_schema.ts @@ -49,18 +49,10 @@ export const MANIFEST_V2: JSONSchema = { `, }, group: { - enum: ['common', 'platform', 'observability', 'security', 'search'], + enum: ['platform', 'observability', 'security', 'search'], description: desc` Specifies the group to which this module pertains. `, - default: 'common', - }, - visibility: { - enum: ['private', 'shared'], - description: desc` - Specifies the visibility of this module, i.e. whether it can be accessed by everybody or only modules in the same group - `, - default: 'shared', }, devOnly: { type: 'boolean', @@ -112,6 +104,37 @@ export const MANIFEST_V2: JSONSchema = { type: 'string', }, }, + allOf: [ + { + if: { + properties: { group: { const: 'platform' } }, + }, + then: { + properties: { + visibility: { + enum: ['private', 'shared'], + description: desc` + Specifies the visibility of this module, i.e. whether it can be accessed by everybody or only modules in the same group + `, + default: 'shared', + }, + }, + required: ['visibility'], + }, + else: { + properties: { + visibility: { + const: 'private', + description: desc` + Specifies the visibility of this module, i.e. whether it can be accessed by everybody or only modules in the same group + `, + default: 'private', + }, + }, + required: ['visibility'], + }, + }, + ], oneOf: [ { type: 'object', diff --git a/packages/kbn-management/settings/setting_ids/index.ts b/packages/kbn-management/settings/setting_ids/index.ts index b146be6f6e25..bc0f7206a283 100644 --- a/packages/kbn-management/settings/setting_ids/index.ts +++ b/packages/kbn-management/settings/setting_ids/index.ts @@ -34,7 +34,6 @@ export const HISTOGRAM_BAR_TARGET_ID = 'histogram:barTarget'; export const HISTOGRAM_MAX_BARS_ID = 'histogram:maxBars'; export const HISTORY_LIMIT_ID = 'history:limit'; export const META_FIELDS_ID = 'metaFields'; -export const METRICS_ALLOW_CHECKING_FOR_FAILED_SHARDS_ID = 'metrics:allowCheckingForFailedShards'; export const METRICS_ALLOW_STRING_INDICES_ID = 'metrics:allowStringIndices'; export const METRICS_MAX_BUCKETS_ID = 'metrics:max_buckets'; export const QUERY_ALLOW_LEADING_WILDCARDS_ID = 'query:allowLeadingWildcards'; diff --git a/packages/kbn-monaco/src/esql/lib/esql_theme.ts b/packages/kbn-monaco/src/esql/lib/esql_theme.ts index bf5e2c597eb6..330e55de8615 100644 --- a/packages/kbn-monaco/src/esql/lib/esql_theme.ts +++ b/packages/kbn-monaco/src/esql/lib/esql_theme.ts @@ -74,7 +74,6 @@ export const buildESQlTheme = (): monaco.editor.IStandaloneThemeData => ({ 'asc', 'desc', 'nulls_order', - 'match', ], euiThemeVars.euiColorAccentText, true // isBold diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 432211d395f6..aca3a1a0c3c9 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -2,7 +2,7 @@ pageLoadAssetSize: actions: 20000 advancedSettings: 27596 aiAssistantManagementSelection: 19146 - aiops: 10000 + aiops: 16000 alerting: 106936 apm: 64385 banners: 17946 @@ -33,7 +33,7 @@ pageLoadAssetSize: dataViewFieldEditor: 42021 dataViewManagement: 5300 dataViews: 65000 - dataVisualizer: 27530 + dataVisualizer: 30000 devTools: 38637 discover: 99999 discoverEnhanced: 42730 @@ -119,7 +119,7 @@ pageLoadAssetSize: observabilityAiAssistantManagement: 19279 observabilityLogsExplorer: 46650 observabilityOnboarding: 19573 - observabilityShared: 80000 + observabilityShared: 111036 osquery: 107090 painlessLab: 179748 presentationPanel: 55463 diff --git a/packages/kbn-screenshotting-server/src/paths.ts b/packages/kbn-screenshotting-server/src/paths.ts index 9e8200c0839a..e4c5a89d7762 100644 --- a/packages/kbn-screenshotting-server/src/paths.ts +++ b/packages/kbn-screenshotting-server/src/paths.ts @@ -46,10 +46,10 @@ export class ChromiumArchivePaths { platform: 'darwin', architecture: 'x64', archiveFilename: 'chrome-mac.zip', - archiveChecksum: '0a3d18efd00b3406f66139a673616b4b2b4b00323776678cb82295996f5a6733', - binaryChecksum: '8bcdaa973ee11110f6b70eaac2418fda3bb64446cf37f964fce331cdc8907a20', + archiveChecksum: '04f0132019c15660eea0b9d261fd14940c33b625c253689fcb5b09d58c4dbfe7', + binaryChecksum: 'a3ada6874ee052c096f09481fba75fcdabb96a8a9ad94a96949946a2485feccf', binaryRelativePath: 'chrome-mac/Chromium.app/Contents/MacOS/Chromium', - revision: 1331485, // 1331488 is not available for Mac_x64 + revision: 1355985, location: 'common', archivePath: 'Mac', isPreInstalled: false, @@ -58,10 +58,10 @@ export class ChromiumArchivePaths { platform: 'darwin', architecture: 'arm64', archiveFilename: 'chrome-mac.zip', - archiveChecksum: '426eddf16acb88b9446a91de53cc4364c7d487414248f33e30f68cf488cea0c0', - binaryChecksum: '827931739bfdd2b6790a81d5ade8886c159cd051581d79b84d1ede447293e9cf', + archiveChecksum: '6c75bb645696aed0e60b17e0e50423b97d21ca11f2c5cdfbaf17edbf582cec94', + binaryChecksum: '2f819f59379917056e07d640f75b1dbe22a830c2655e32ab0543013b7198c139', binaryRelativePath: 'chrome-mac/Chromium.app/Contents/MacOS/Chromium', - revision: 1331488, + revision: 1355985, location: 'common', archivePath: 'Mac_Arm', isPreInstalled: false, @@ -69,22 +69,22 @@ export class ChromiumArchivePaths { { platform: 'linux', architecture: 'x64', - archiveFilename: 'chromium-fe621c5-locales-linux_x64.zip', - archiveChecksum: '12ce2e0eac184072dfcbc7a267328e3eb7fbe10a682997f4111c0378f2397341', - binaryChecksum: '670481cfa8db209401106cd23051009d390c03608724d0822a12c8c0a92b4c25', + archiveFilename: 'chromium-53ac076-locales-linux_x64.zip', + archiveChecksum: '50424bf105710d184198484a8a666db414627596002dacf80e83b00c8da71115', + binaryChecksum: 'afbc87a7f946bd6df763ffffb38dd4d75ee50c28ba705ac177dc893030d20206', binaryRelativePath: 'headless_shell-linux_x64/headless_shell', - revision: 1331488, + revision: 1356013, location: 'custom', isPreInstalled: true, }, { platform: 'linux', architecture: 'arm64', - archiveFilename: 'chromium-fe621c5-locales-linux_arm64.zip', - archiveChecksum: 'f7333eaff5235046c8775f0c1a0b7395b7ebc2e054ea638710cf511c4b6f9daf', - binaryChecksum: '8a3a3371b3d04f4b0880b137a3611c223e0d8e65a218943cb7be1ec4a91f5e35', + archiveFilename: 'chromium-53ac076-locales-linux_arm64.zip', + archiveChecksum: '24ffa183a6bf355209f3960a2377a1f8cc75aef093fe1934fcc72d2a5f9a274b', + binaryChecksum: 'db1c0226e03dfc26a6d61e02a885912906529e8477ac3214962b160d1e99f25c', binaryRelativePath: 'headless_shell-linux_arm64/headless_shell', - revision: 1331488, + revision: 1356013, location: 'custom', isPreInstalled: true, }, @@ -92,10 +92,10 @@ export class ChromiumArchivePaths { platform: 'win32', architecture: 'x64', archiveFilename: 'chrome-win.zip', - archiveChecksum: 'fa62be702f55f37e455bab4291c59ceb40e81e1922d30cf9453a4ee176b909bc', - binaryChecksum: '1345e66583bad1a1f16885f381d1173de8bf931487da9ba155e1b58bf23b2c66', + archiveChecksum: 'f86aadca5d1ab02fc05b580f23a30ee02d34bd348f9a3f0032b7117027676727', + binaryChecksum: 'b7b98dd681dfea2333a0136ba5788e38010730bb2e42eafa291b16931f00449d', binaryRelativePath: path.join('chrome-win', 'chrome.exe'), - revision: 1331487, // 1331488 is not available for win32 + revision: 1355984, location: 'common', archivePath: 'Win', isPreInstalled: true, diff --git a/packages/kbn-search-types/src/types.ts b/packages/kbn-search-types/src/types.ts index 0f6f3ecc9c06..0f19dff76ccf 100644 --- a/packages/kbn-search-types/src/types.ts +++ b/packages/kbn-search-types/src/types.ts @@ -114,6 +114,11 @@ export interface ISearchOptions { * To pass an abort signal, use {@link ISearchOptions.abortSignal} */ transport?: Omit; + + /** + * When set es results are streamed back to the caller without any parsing of the content. + */ + stream?: boolean; } /** @@ -130,4 +135,5 @@ export type ISearchOptionsSerializable = Pick< | 'isRestore' | 'retrieveResults' | 'executionContext' + | 'stream' >; diff --git a/packages/kbn-securitysolution-autocomplete/index.ts b/packages/kbn-securitysolution-autocomplete/index.ts index fef857773701..e47113719176 100644 --- a/packages/kbn-securitysolution-autocomplete/index.ts +++ b/packages/kbn-securitysolution-autocomplete/index.ts @@ -8,7 +8,7 @@ */ export * from './src/check_empty_value'; -export * from './src/field'; +export * from './src/es_field_selector'; export * from './src/field_value_exists'; export * from './src/field_value_lists'; export * from './src/field_value_match'; diff --git a/packages/kbn-securitysolution-autocomplete/src/field/__tests__/__snapshots__/index.test.tsx.snap b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/__snapshots__/index.test.tsx.snap similarity index 100% rename from packages/kbn-securitysolution-autocomplete/src/field/__tests__/__snapshots__/index.test.tsx.snap rename to packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/__snapshots__/index.test.tsx.snap diff --git a/packages/kbn-securitysolution-autocomplete/src/field/__tests__/disabled_types_with_tooltip_text.test.ts b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/disabled_types_with_tooltip_text.test.ts similarity index 100% rename from packages/kbn-securitysolution-autocomplete/src/field/__tests__/disabled_types_with_tooltip_text.test.ts rename to packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/disabled_types_with_tooltip_text.test.ts diff --git a/packages/kbn-securitysolution-autocomplete/src/field/__tests__/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/index.test.tsx similarity index 96% rename from packages/kbn-securitysolution-autocomplete/src/field/__tests__/index.test.tsx rename to packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/index.test.tsx index b795abc5842f..1b33b4b29464 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field/__tests__/index.test.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/__tests__/index.test.tsx @@ -11,13 +11,13 @@ import React from 'react'; import { fireEvent, render, waitFor, within } from '@testing-library/react'; import '@testing-library/jest-dom'; -import { FieldComponent } from '..'; +import { EsFieldSelector } from '..'; import { fields, getField } from '../../fields/index.mock'; describe('FieldComponent', () => { it('should render the component enabled and displays the selected field correctly', () => { const wrapper = render( - { }); it('should render the component disabled if isDisabled is true', () => { const wrapper = render( - { }); it('should render the loading spinner if isLoading is true when clicked', () => { const wrapper = render( - { }); it('should allow user to clear values if isClearable is true', () => { const wrapper = render( - { }); it('should change the selected value', async () => { const wrapper = render( - { it('it allows custom user input if "acceptsCustomOptions" is "true"', async () => { const mockOnChange = jest.fn(); const wrapper = render( - ({ BINARY_TYPE_NOT_SUPPORTED: 'Binary fields are currently unsupported', @@ -33,7 +33,7 @@ describe('useField', () => { describe('comboOptions and selectedComboOptions', () => { it('should return default values', () => { - const { result } = renderHook(() => useField({ indexPattern, onChange: onChangeMock })); + const { result } = renderHook(() => useEsField({ indexPattern, onChange: onChangeMock })); const { isInvalid, comboOptions, selectedComboOptions, fieldWidth } = result.current; expect(isInvalid).toBeFalsy(); expect(comboOptions.length).toEqual(30); @@ -79,7 +79,7 @@ describe('useField', () => { }; const { result } = renderHook(() => - useField({ indexPattern: newIndexPattern, onChange: onChangeMock }) + useEsField({ indexPattern: newIndexPattern, onChange: onChangeMock }) ); const { comboOptions, selectedComboOptions } = result.current; expect(comboOptions).toEqual([{ label: 'bytes' }, { label: 'ssl' }, { label: '@timestamp' }]); @@ -124,7 +124,7 @@ describe('useField', () => { }; const { result } = renderHook(() => - useField({ + useEsField({ indexPattern: newIndexPattern, onChange: onChangeMock, selectedField: { name: '', type: 'keyword' }, @@ -173,7 +173,7 @@ describe('useField', () => { }; const { result } = renderHook(() => - useField({ + useEsField({ indexPattern: newIndexPattern, onChange: onChangeMock, selectedField: { name: ' ', type: 'keyword' }, @@ -222,7 +222,7 @@ describe('useField', () => { }; const { result } = renderHook(() => - useField({ indexPattern: newIndexPattern, onChange: onChangeMock, selectedField }) + useEsField({ indexPattern: newIndexPattern, onChange: onChangeMock, selectedField }) ); const { comboOptions, selectedComboOptions } = result.current; expect(comboOptions).toEqual([{ label: 'bytes' }, { label: 'ssl' }, { label: '@timestamp' }]); @@ -273,7 +273,7 @@ describe('useField', () => { readFromDocValues: true, }, ] as unknown as DataViewFieldBase[]; - const { result } = renderHook(() => useField({ indexPattern, onChange: onChangeMock })); + const { result } = renderHook(() => useEsField({ indexPattern, onChange: onChangeMock })); const { comboOptions, renderFields } = result.current; expect(comboOptions).toEqual([ { label: 'blob' }, @@ -328,7 +328,7 @@ describe('useField', () => { readFromDocValues: true, }, ] as unknown as DataViewFieldBase[]; - const { result } = renderHook(() => useField({ indexPattern, onChange: onChangeMock })); + const { result } = renderHook(() => useEsField({ indexPattern, onChange: onChangeMock })); const { comboOptions, renderFields } = result.current; expect(comboOptions).toEqual([ { label: 'blob' }, @@ -374,7 +374,7 @@ describe('useField', () => { readFromDocValues: true, }, ] as unknown as DataViewFieldBase[]; - const { result } = renderHook(() => useField({ indexPattern, onChange: onChangeMock })); + const { result } = renderHook(() => useEsField({ indexPattern, onChange: onChangeMock })); const { comboOptions, renderFields } = result.current; expect(comboOptions).toEqual([{ label: 'bytes' }, { label: 'ssl' }, { label: '@timestamp' }]); act(() => { @@ -389,7 +389,7 @@ describe('useField', () => { jest.resetModules(); }); it('should invoke onChange with one value if one option is sent', () => { - const { result } = renderHook(() => useField({ indexPattern, onChange: onChangeMock })); + const { result } = renderHook(() => useEsField({ indexPattern, onChange: onChangeMock })); act(() => { result.current.handleValuesChange([ { @@ -411,7 +411,7 @@ describe('useField', () => { }); }); it('should invoke onChange with array value if more than an option', () => { - const { result } = renderHook(() => useField({ indexPattern, onChange: onChangeMock })); + const { result } = renderHook(() => useEsField({ indexPattern, onChange: onChangeMock })); act(() => { result.current.handleValuesChange([ { @@ -446,7 +446,7 @@ describe('useField', () => { }); }); it('should invoke onChange with custom option if one is sent', () => { - const { result } = renderHook(() => useField({ indexPattern, onChange: onChangeMock })); + const { result } = renderHook(() => useEsField({ indexPattern, onChange: onChangeMock })); act(() => { result.current.handleCreateCustomOption('madeUpField'); expect(onChangeMock).toHaveBeenCalledWith([ @@ -462,13 +462,13 @@ describe('useField', () => { describe('fieldWidth', () => { it('should return object has width prop', () => { const { result } = renderHook(() => - useField({ indexPattern, onChange: onChangeMock, fieldInputWidth: 100 }) + useEsField({ indexPattern, onChange: onChangeMock, fieldInputWidth: 100 }) ); expect(result.current.fieldWidth).toEqual({ width: '100px' }); }); it('should return empty object', () => { const { result } = renderHook(() => - useField({ indexPattern, onChange: onChangeMock, fieldInputWidth: 0 }) + useEsField({ indexPattern, onChange: onChangeMock, fieldInputWidth: 0 }) ); expect(result.current.fieldWidth).toEqual({}); }); @@ -477,7 +477,7 @@ describe('useField', () => { describe('isInvalid with handleTouch', () => { it('should return isInvalid equals true when calling with no selectedField and isRequired is true', () => { const { result } = renderHook(() => - useField({ indexPattern, onChange: onChangeMock, isRequired: true }) + useEsField({ indexPattern, onChange: onChangeMock, isRequired: true }) ); actTestRenderer(() => { @@ -487,7 +487,7 @@ describe('useField', () => { }); it('should return isInvalid equals false with selectedField and isRequired is true', () => { const { result } = renderHook(() => - useField({ indexPattern, onChange: onChangeMock, isRequired: true, selectedField }) + useEsField({ indexPattern, onChange: onChangeMock, isRequired: true, selectedField }) ); actTestRenderer(() => { @@ -496,7 +496,7 @@ describe('useField', () => { expect(result.current.isInvalid).toBeFalsy(); }); it('should return isInvalid equals false when isRequired is false', () => { - const { result } = renderHook(() => useField({ indexPattern, onChange: onChangeMock })); + const { result } = renderHook(() => useEsField({ indexPattern, onChange: onChangeMock })); actTestRenderer(() => { result.current.handleTouch(); diff --git a/packages/kbn-securitysolution-autocomplete/src/field/disabled_types_with_tooltip_text.ts b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/disabled_types_with_tooltip_text.ts similarity index 100% rename from packages/kbn-securitysolution-autocomplete/src/field/disabled_types_with_tooltip_text.ts rename to packages/kbn-securitysolution-autocomplete/src/es_field_selector/disabled_types_with_tooltip_text.ts diff --git a/packages/kbn-securitysolution-autocomplete/src/field/index.tsx b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/index.tsx similarity index 85% rename from packages/kbn-securitysolution-autocomplete/src/field/index.tsx rename to packages/kbn-securitysolution-autocomplete/src/es_field_selector/index.tsx index 7c830264af30..31efaa23b62d 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field/index.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/index.tsx @@ -11,12 +11,22 @@ import React from 'react'; import { EuiComboBox } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FieldProps } from './types'; -import { useField } from './use_field'; +import { FieldBaseProps } from './types'; +import { useEsField } from './use_es_field'; const AS_PLAIN_TEXT = { asPlainText: true }; -export const FieldComponent: React.FC = ({ +interface EsFieldSelectorProps extends FieldBaseProps { + isClearable?: boolean; + isDisabled?: boolean; + isLoading?: boolean; + placeholder: string; + acceptsCustomOptions?: boolean; + showMappingConflicts?: boolean; + 'aria-label'?: string; +} + +export function EsFieldSelector({ fieldInputWidth, fieldTypeFilter = [], indexPattern, @@ -30,18 +40,17 @@ export const FieldComponent: React.FC = ({ acceptsCustomOptions = false, showMappingConflicts = false, 'aria-label': ariaLabel, -}): JSX.Element => { +}: EsFieldSelectorProps): JSX.Element { const { isInvalid, comboOptions, selectedComboOptions, fieldWidth, - renderFields, handleTouch, handleValuesChange, handleCreateCustomOption, - } = useField({ + } = useEsField({ indexPattern, fieldTypeFilter, isRequired, @@ -97,6 +106,4 @@ export const FieldComponent: React.FC = ({ aria-label={ariaLabel} /> ); -}; - -FieldComponent.displayName = 'Field'; +} diff --git a/packages/kbn-securitysolution-autocomplete/src/field/types.ts b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/types.ts similarity index 85% rename from packages/kbn-securitysolution-autocomplete/src/field/types.ts rename to packages/kbn-securitysolution-autocomplete/src/es_field_selector/types.ts index 26e0eb969770..b0f1ab56e807 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field/types.ts +++ b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/types.ts @@ -11,15 +11,6 @@ import { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; import { FieldConflictsInfo } from '@kbn/securitysolution-list-utils'; import { GetGenericComboBoxPropsReturn } from '../get_generic_combo_box_props'; -export interface FieldProps extends FieldBaseProps { - isClearable: boolean; - isDisabled: boolean; - isLoading: boolean; - placeholder: string; - acceptsCustomOptions?: boolean; - showMappingConflicts?: boolean; - 'aria-label'?: string; -} export interface FieldBaseProps { indexPattern: DataViewBase | undefined; fieldTypeFilter?: string[]; diff --git a/packages/kbn-securitysolution-autocomplete/src/field/use_field.tsx b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/use_es_field.tsx similarity index 99% rename from packages/kbn-securitysolution-autocomplete/src/field/use_field.tsx rename to packages/kbn-securitysolution-autocomplete/src/es_field_selector/use_es_field.tsx index 7a0b7eb5b00a..615571d98960 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field/use_field.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/es_field_selector/use_es_field.tsx @@ -115,7 +115,7 @@ const getComboBoxProps = (fields: ComboBoxFields): GetFieldComboBoxPropsReturn = }; }; -export const useField = ({ +export const useEsField = ({ indexPattern, fieldTypeFilter, isRequired, diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx index 6a831376b3cb..5b627451db19 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.tsx @@ -48,9 +48,9 @@ interface AutocompleteFieldMatchProps { selectedField: DataViewFieldBase | undefined; selectedValue: string | undefined; indexPattern: DataViewBase | undefined; - isLoading: boolean; - isDisabled: boolean; - isClearable: boolean; + isLoading?: boolean; + isDisabled?: boolean; + isClearable?: boolean; isRequired?: boolean; fieldInputWidth?: number; rowLabel?: string; @@ -68,7 +68,7 @@ export const AutocompleteFieldMatchComponent: React.FC
{ }); } + // This is a workaround to run tests with React 17 and the latest @testing-library/react + // This will be removed once we upgrade to React 18 and start transitioning to the Concurrent Mode + // Tracking issue to clean this up https://github.com/elastic/kibana/issues/199100 + if (request === 'react-dom/client') { + return Path.resolve(__dirname, 'mocks/react_dom_client_mock.ts'); + } + if (request === `elastic-apm-node`) { return APM_AGENT_MOCK; } diff --git a/packages/kbn-test/src/jest/setup/react_testing_library.js b/packages/kbn-test/src/jest/setup/react_testing_library.js index a04ee097a5ec..1444aa41949e 100644 --- a/packages/kbn-test/src/jest/setup/react_testing_library.js +++ b/packages/kbn-test/src/jest/setup/react_testing_library.js @@ -19,3 +19,34 @@ import { configure } from '@testing-library/react'; // instead of default 'data-testid', use kibana's 'data-test-subj' configure({ testIdAttribute: 'data-test-subj', asyncUtilTimeout: 4500 }); + +/* eslint-env jest */ + +// This is a workaround to run tests with React 17 and the latest @testing-library/react +// Tracking issue to clean this up https://github.com/elastic/kibana/issues/199100 +jest.mock('@testing-library/react', () => { + const actual = jest.requireActual('@testing-library/react'); + + return { + ...actual, + render: (ui, options) => actual.render(ui, { ...options, legacyRoot: true }), + renderHook: (render, options) => actual.renderHook(render, { ...options, legacyRoot: true }), + }; +}); + +// This is a workaround to run tests with React 17 and the latest @testing-library/react +// And prevent the act warnings that were supposed to be muted by @testing-library +// The testing library mutes the act warnings in some cases by setting IS_REACT_ACT_ENVIRONMENT which is React@18 feature https://github.com/testing-library/react-testing-library/pull/1137/ +// Using this console override we're muting the act warnings as well +// Tracking issue to clean this up https://github.com/elastic/kibana/issues/199100 +// NOTE: we're not muting all the act warnings but only those that testing-library wanted to mute +const originalConsoleError = console.error; +console.error = (...args) => { + if (global.IS_REACT_ACT_ENVIRONMENT === false) { + if (args[0].includes('Warning: An update to %s inside a test was not wrapped in act')) { + return; + } + } + + originalConsoleError(...args); +}; diff --git a/packages/kbn-test/src/kbn_client/kbn_client_saved_objects.ts b/packages/kbn-test/src/kbn_client/kbn_client_saved_objects.ts index d5483f1fe0f9..0b6ba0be80fa 100644 --- a/packages/kbn-test/src/kbn_client/kbn_client_saved_objects.ts +++ b/packages/kbn-test/src/kbn_client/kbn_client_saved_objects.ts @@ -109,6 +109,7 @@ const STANDARD_LIST_TYPES = [ 'synthetics-monitor', 'uptime-dynamic-settings', 'synthetics-privates-locations', + 'synthetics-private-location', 'osquery-saved-query', 'osquery-pack', diff --git a/packages/kbn-unified-field-list/src/components/field_popover/field_popover_header.test.tsx b/packages/kbn-unified-field-list/src/components/field_popover/field_popover_header.test.tsx index 19fee33bc6ea..a4e322f2b681 100644 --- a/packages/kbn-unified-field-list/src/components/field_popover/field_popover_header.test.tsx +++ b/packages/kbn-unified-field-list/src/components/field_popover/field_popover_header.test.tsx @@ -38,6 +38,7 @@ describe('UnifiedFieldList ', () => { field={field} closePopover={mockClose} onAddFieldToWorkspace={jest.fn()} + onAddBreakdownField={jest.fn()} onAddFilter={jest.fn()} onEditField={jest.fn()} onDeleteField={jest.fn()} @@ -45,6 +46,9 @@ describe('UnifiedFieldList ', () => { ); expect(wrapper.text()).toBe(fieldName); + expect( + wrapper.find(`[data-test-subj="fieldPopoverHeader_addBreakdownField-${fieldName}"]`).exists() + ).toBeTruthy(); expect( wrapper.find(`[data-test-subj="fieldPopoverHeader_addField-${fieldName}"]`).exists() ).toBeTruthy(); @@ -57,7 +61,29 @@ describe('UnifiedFieldList ', () => { expect( wrapper.find(`[data-test-subj="fieldPopoverHeader_deleteField-${fieldName}"]`).exists() ).toBeTruthy(); - expect(wrapper.find(EuiButtonIcon)).toHaveLength(4); + expect(wrapper.find(EuiButtonIcon)).toHaveLength(5); + }); + + it('should correctly handle add-breakdown-field action', async () => { + const mockClose = jest.fn(); + const mockAddBreakdownField = jest.fn(); + const fieldName = 'extension'; + const field = dataView.fields.find((f) => f.name === fieldName)!; + const wrapper = mountWithIntl( + + ); + + wrapper + .find(`[data-test-subj="fieldPopoverHeader_addBreakdownField-${fieldName}"]`) + .first() + .simulate('click'); + + expect(mockClose).toHaveBeenCalled(); + expect(mockAddBreakdownField).toHaveBeenCalledWith(field); }); it('should correctly handle add-field action', async () => { diff --git a/packages/kbn-unified-field-list/src/components/field_popover/field_popover_header.tsx b/packages/kbn-unified-field-list/src/components/field_popover/field_popover_header.tsx index 65d5a1da9803..3babd0587191 100644 --- a/packages/kbn-unified-field-list/src/components/field_popover/field_popover_header.tsx +++ b/packages/kbn-unified-field-list/src/components/field_popover/field_popover_header.tsx @@ -31,6 +31,7 @@ export interface FieldPopoverHeaderProps { buttonAddFilterProps?: Partial; buttonEditFieldProps?: Partial; buttonDeleteFieldProps?: Partial; + onAddBreakdownField?: (field: DataViewField | undefined) => void; onAddFieldToWorkspace?: (field: DataViewField) => unknown; onAddFilter?: AddFieldFilterHandler; onEditField?: (fieldName: string) => unknown; @@ -47,6 +48,7 @@ export const FieldPopoverHeader: React.FC = ({ buttonAddFilterProps, buttonEditFieldProps, buttonDeleteFieldProps, + onAddBreakdownField, onAddFieldToWorkspace, onAddFilter, onEditField, @@ -82,6 +84,13 @@ export const FieldPopoverHeader: React.FC = ({ defaultMessage: 'Delete data view field', }); + const addBreakdownFieldTooltip = i18n.translate( + 'unifiedFieldList.fieldPopover.addBreakdownFieldLabel', + { + defaultMessage: 'Add breakdown', + } + ); + return ( <> @@ -108,6 +117,21 @@ export const FieldPopoverHeader: React.FC = ({ )} + {onAddBreakdownField && ( + + + { + closePopover(); + onAddBreakdownField(field); + }} + /> + + + )} {onAddFilter && field.filterable && !field.scripted && ( diff --git a/packages/kbn-unified-field-list/src/components/field_stats/field_stats.test.tsx b/packages/kbn-unified-field-list/src/components/field_stats/field_stats.test.tsx index 951602334a62..beb0e1f05e1b 100644 --- a/packages/kbn-unified-field-list/src/components/field_stats/field_stats.test.tsx +++ b/packages/kbn-unified-field-list/src/components/field_stats/field_stats.test.tsx @@ -830,4 +830,14 @@ describe('UnifiedFieldList FieldStats', () => { expect(wrapper.text()).toBe('Summarymin29674max36821994Calculated from 5000 sample records.'); }); + + it('should not request field stats for ES|QL query', async () => { + const wrapper = await mountComponent( + + ); + + expect(loadFieldStats).toHaveBeenCalledTimes(0); + + expect(wrapper.text()).toBe('Analysis is not available for this field.'); + }); }); diff --git a/packages/kbn-unified-field-list/src/components/field_stats/field_stats.tsx b/packages/kbn-unified-field-list/src/components/field_stats/field_stats.tsx index 8eada232cdea..58ff36069dd8 100755 --- a/packages/kbn-unified-field-list/src/components/field_stats/field_stats.tsx +++ b/packages/kbn-unified-field-list/src/components/field_stats/field_stats.tsx @@ -42,7 +42,6 @@ import { canProvideNumberSummaryForField, } from '../../utils/can_provide_stats'; import { loadFieldStats } from '../../services/field_stats'; -import { loadFieldStatsTextBased } from '../../services/field_stats_text_based'; import type { AddFieldFilterHandler } from '../../types'; import { FieldTopValues, @@ -136,7 +135,7 @@ const FieldStatsComponent: React.FC = ({ const [dataView, changeDataView] = useState(null); const abortControllerRef = useRef(null); const isCanceledRef = useRef(false); - const isTextBased = !!query && isOfAggregateQueryType(query); + const isEsqlQuery = !!query && isOfAggregateQueryType(query); const setState: typeof changeState = useCallback( (nextState) => { @@ -178,6 +177,12 @@ const FieldStatsComponent: React.FC = ({ setDataView(loadedDataView); + if (isEsqlQuery) { + // Not supported yet for ES|QL queries + // Previous implementation was removed in https://github.com/elastic/kibana/pull/198948/ + return; + } + if (state.isLoading) { return; } @@ -187,32 +192,17 @@ const FieldStatsComponent: React.FC = ({ abortControllerRef.current?.abort(); abortControllerRef.current = new AbortController(); - const results = isTextBased - ? await loadFieldStatsTextBased({ - services: { data }, - dataView: loadedDataView, - field, - fromDate, - toDate, - baseQuery: query, - abortController: abortControllerRef.current, - }) - : await loadFieldStats({ - services: { data }, - dataView: loadedDataView, - field, - fromDate, - toDate, - dslQuery: - dslQuery ?? - buildEsQuery( - loadedDataView, - query ?? [], - filters ?? [], - getEsQueryConfig(uiSettings) - ), - abortController: abortControllerRef.current, - }); + const results = await loadFieldStats({ + services: { data }, + dataView: loadedDataView, + field, + fromDate, + toDate, + dslQuery: + dslQuery ?? + buildEsQuery(loadedDataView, query ?? [], filters ?? [], getEsQueryConfig(uiSettings)), + abortController: abortControllerRef.current, + }); abortControllerRef.current = null; @@ -297,7 +287,7 @@ const FieldStatsComponent: React.FC = ({ let title = <>; function combineWithTitleAndFooter(el: React.ReactElement) { - const countsElement = getCountsElement(state, services, isTextBased, dataTestSubject); + const countsElement = getCountsElement(state, services, isEsqlQuery, dataTestSubject); return ( <> @@ -319,7 +309,7 @@ const FieldStatsComponent: React.FC = ({ ); } - if (!canProvideStatsForField(field, isTextBased)) { + if (!canProvideStatsForField(field, isEsqlQuery)) { const messageNoAnalysis = ( = ({ : messageNoAnalysis; } - if (canProvideNumberSummaryForField(field, isTextBased) && isNumberSummaryValid(numberSummary)) { + if (canProvideNumberSummaryForField(field, isEsqlQuery) && isNumberSummaryValid(numberSummary)) { title = (
@@ -563,21 +553,19 @@ const FieldStatsComponent: React.FC = ({ function getCountsElement( state: FieldStatsState, services: FieldStatsServices, - isTextBased: boolean, + isEsqlQuery: boolean, dataTestSubject: string ): JSX.Element { const dataTestSubjDocsCount = 'unifiedFieldStats-statsFooter-docsCount'; const { fieldFormats } = services; - const { totalDocuments, sampledValues, sampledDocuments, topValues } = state; + const { totalDocuments, sampledDocuments } = state; - if (!totalDocuments) { + if (!totalDocuments || isEsqlQuery) { return <>; } - let labelElement; - - if (isTextBased) { - labelElement = topValues?.areExamples ? ( + const labelElement = + sampledDocuments && sampledDocuments < totalDocuments ? ( ) : ( {fieldFormats .getDefaultInstance(KBN_FIELD_TYPES.NUMBER, [ES_FIELD_TYPES.INTEGER]) - .convert(sampledValues)} + .convert(totalDocuments)} ), }} /> ); - } else { - labelElement = - sampledDocuments && sampledDocuments < totalDocuments ? ( - - {fieldFormats - .getDefaultInstance(KBN_FIELD_TYPES.NUMBER, [ES_FIELD_TYPES.INTEGER]) - .convert(sampledDocuments)} - - ), - }} - /> - ) : ( - - {fieldFormats - .getDefaultInstance(KBN_FIELD_TYPES.NUMBER, [ES_FIELD_TYPES.INTEGER]) - .convert(totalDocuments)} - - ), - }} - /> - ); - } return ( diff --git a/packages/kbn-unified-field-list/src/containers/unified_field_list_item/field_list_item.test.tsx b/packages/kbn-unified-field-list/src/containers/unified_field_list_item/field_list_item.test.tsx index a5b1955aeca2..671a4175ad10 100644 --- a/packages/kbn-unified-field-list/src/containers/unified_field_list_item/field_list_item.test.tsx +++ b/packages/kbn-unified-field-list/src/containers/unified_field_list_item/field_list_item.test.tsx @@ -43,10 +43,12 @@ async function getComponent({ selected = false, field, canFilter = true, + isBreakdownSupported = true, }: { selected?: boolean; field?: DataViewField; canFilter?: boolean; + isBreakdownSupported?: boolean; }) { const finalField = field ?? @@ -76,6 +78,7 @@ async function getComponent({ dataView: stubDataView, field: finalField, ...(canFilter && { onAddFilter: jest.fn() }), + ...(isBreakdownSupported && { onAddBreakdownField: jest.fn() }), onAddFieldToWorkspace: jest.fn(), onRemoveFieldFromWorkspace: jest.fn(), onEditField: jest.fn(), @@ -137,6 +140,34 @@ describe('UnifiedFieldListItem', function () { expect(comp.find(FieldItemButton).prop('onClick')).toBeUndefined(); }); + + it('should not show addBreakdownField action button if not supported', async function () { + const field = new DataViewField({ + name: 'extension.keyword', + type: 'string', + esTypes: ['keyword'], + aggregatable: true, + searchable: true, + }); + const { comp } = await getComponent({ + field, + isBreakdownSupported: false, + }); + + await act(async () => { + const fieldItem = findTestSubject(comp, 'field-extension.keyword-showDetails'); + await fieldItem.simulate('click'); + await comp.update(); + }); + + await comp.update(); + + expect( + comp + .find('[data-test-subj="fieldPopoverHeader_addBreakdownField-extension.keyword"]') + .exists() + ).toBeFalsy(); + }); it('should request field stats', async function () { const field = new DataViewField({ name: 'machine.os.raw', @@ -189,6 +220,11 @@ describe('UnifiedFieldListItem', function () { await comp.update(); expect(comp.find(EuiPopover).prop('isOpen')).toBe(true); + expect( + comp + .find('[data-test-subj="fieldPopoverHeader_addBreakdownField-extension.keyword"]') + .exists() + ).toBeTruthy(); expect( comp.find('[data-test-subj="fieldPopoverHeader_addField-extension.keyword"]').exists() ).toBeTruthy(); diff --git a/packages/kbn-unified-field-list/src/containers/unified_field_list_item/field_list_item.tsx b/packages/kbn-unified-field-list/src/containers/unified_field_list_item/field_list_item.tsx index 7864976c1180..2ff7d22de39d 100644 --- a/packages/kbn-unified-field-list/src/containers/unified_field_list_item/field_list_item.tsx +++ b/packages/kbn-unified-field-list/src/containers/unified_field_list_item/field_list_item.tsx @@ -15,6 +15,8 @@ import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/publ import { Draggable } from '@kbn/dom-drag-drop'; import type { DataView, DataViewField } from '@kbn/data-views-plugin/public'; import { Filter } from '@kbn/es-query'; +import { fieldSupportsBreakdown } from '@kbn/field-utils'; +import { isESQLFieldGroupable } from '@kbn/esql-utils'; import type { SearchMode } from '../../types'; import { FieldItemButton, type FieldItemButtonProps } from '../../components/field_item_button'; import { @@ -32,7 +34,7 @@ import type { UnifiedFieldListSidebarContainerStateService, AddFieldFilterHandler, } from '../../types'; -import { canProvideStatsForFieldTextBased } from '../../utils/can_provide_stats'; +import { canProvideStatsForEsqlField } from '../../utils/can_provide_stats'; interface GetCommonFieldItemButtonPropsParams { stateService: UnifiedFieldListSidebarContainerStateService; @@ -140,6 +142,10 @@ export interface UnifiedFieldListItemProps { * The currently selected data view */ dataView: DataView; + /** + * Callback to update breakdown field + */ + onAddBreakdownField?: (breakdownField: DataViewField | undefined) => void; /** * Callback to add/select the field */ @@ -215,6 +221,7 @@ function UnifiedFieldListItemComponent({ field, highlight, dataView, + onAddBreakdownField, onAddFieldToWorkspace, onRemoveFieldFromWorkspace, onAddFilter, @@ -232,6 +239,9 @@ function UnifiedFieldListItemComponent({ }: UnifiedFieldListItemProps) { const [infoIsOpen, setOpen] = useState(false); + const isBreakdownSupported = + searchMode === 'documents' ? fieldSupportsBreakdown(field) : isESQLFieldGroupable(field); + const addFilterAndClosePopover: typeof onAddFilter | undefined = useMemo( () => onAddFilter @@ -394,18 +404,19 @@ function UnifiedFieldListItemComponent({ data-test-subj={stateService.creationOptions.dataTestSubj?.fieldListItemPopoverDataTestSubj} renderHeader={() => ( )} renderContent={ - (searchMode === 'text-based' && canProvideStatsForFieldTextBased(field)) || + (searchMode === 'text-based' && canProvideStatsForEsqlField(field)) || searchMode === 'documents' ? renderPopover : undefined diff --git a/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar.tsx b/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar.tsx index a7d8fb4616cb..2d23903c34ea 100644 --- a/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar.tsx +++ b/packages/kbn-unified-field-list/src/containers/unified_field_list_sidebar/field_list_sidebar.tsx @@ -48,6 +48,7 @@ export type UnifiedFieldListSidebarCustomizableProps = Pick< | 'dataView' | 'trackUiMetric' | 'onAddFilter' + | 'onAddBreakdownField' | 'onAddFieldToWorkspace' | 'onRemoveFieldFromWorkspace' | 'additionalFilters' @@ -161,6 +162,7 @@ export const UnifiedFieldListSidebarComponent: React.FC (
  • ), @@ -298,6 +301,7 @@ export const UnifiedFieldListSidebarComponent: React.FC + getFieldExampleBuckets({ + values: [['a'], ['b'], ['a'], ['a']], + field: { name: 'message', type: 'string', esTypes: ['text'] } as DataViewField, + isEsqlQuery: true, + }) + ).toThrowError(); expect(() => getFieldExampleBuckets({ values: [['a'], ['b'], ['a'], ['a']], field: { name: 'message', type: 'string', esTypes: ['keyword'] } as DataViewField, - isTextBased: true, + isEsqlQuery: true, }) ).toThrowError(); }); diff --git a/packages/kbn-unified-field-list/src/services/field_examples_calculator/field_examples_calculator.ts b/packages/kbn-unified-field-list/src/services/field_examples_calculator/field_examples_calculator.ts index e4413f3be7fe..55d0c30b58e3 100644 --- a/packages/kbn-unified-field-list/src/services/field_examples_calculator/field_examples_calculator.ts +++ b/packages/kbn-unified-field-list/src/services/field_examples_calculator/field_examples_calculator.ts @@ -23,7 +23,7 @@ export interface FieldValueCountsParams { values: FieldHitValue[]; field: DataViewField; count?: number; - isTextBased: boolean; + isEsqlQuery: boolean; } export function getFieldExampleBuckets(params: FieldValueCountsParams, formatter?: FieldFormat) { @@ -31,7 +31,7 @@ export function getFieldExampleBuckets(params: FieldValueCountsParams, formatter count: DEFAULT_SIMPLE_EXAMPLES_SIZE, }); - if (!canProvideExamplesForField(params.field, params.isTextBased)) { + if (!canProvideExamplesForField(params.field, params.isEsqlQuery)) { throw new Error( `Analysis is not available this field type: "${params.field.type}". Field name: "${params.field.name}"` ); diff --git a/packages/kbn-unified-field-list/src/services/field_stats/field_stats_utils.ts b/packages/kbn-unified-field-list/src/services/field_stats/field_stats_utils.ts index 309f5f054683..57a7d0be8fda 100644 --- a/packages/kbn-unified-field-list/src/services/field_stats/field_stats_utils.ts +++ b/packages/kbn-unified-field-list/src/services/field_stats/field_stats_utils.ts @@ -416,7 +416,7 @@ export async function getSimpleExamples( values: getFieldValues(simpleExamplesResult.hits.hits, field, dataView), field, count: DEFAULT_SIMPLE_EXAMPLES_SIZE, - isTextBased: false, + isEsqlQuery: false, }, formatter ); diff --git a/packages/kbn-unified-field-list/src/services/field_stats_text_based/field_stats_utils_text_based.test.ts b/packages/kbn-unified-field-list/src/services/field_stats_text_based/field_stats_utils_text_based.test.ts deleted file mode 100644 index 553fdd749941..000000000000 --- a/packages/kbn-unified-field-list/src/services/field_stats_text_based/field_stats_utils_text_based.test.ts +++ /dev/null @@ -1,129 +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 type { DataViewField } from '@kbn/data-views-plugin/common'; -import { buildSearchFilter, fetchAndCalculateFieldStats } from './field_stats_utils_text_based'; - -describe('fieldStatsUtilsTextBased', function () { - describe('buildSearchFilter()', () => { - it('should create a time range filter', () => { - expect( - buildSearchFilter({ - timeFieldName: 'timestamp', - fromDate: '2022-12-05T23:00:00.000Z', - toDate: '2023-01-05T09:33:05.359Z', - }) - ).toMatchInlineSnapshot(` - Object { - "range": Object { - "timestamp": Object { - "format": "strict_date_optional_time", - "gte": "2022-12-05T23:00:00.000Z", - "lte": "2023-01-05T09:33:05.359Z", - }, - }, - } - `); - }); - it('should not create a time range filter', () => { - expect( - buildSearchFilter({ - timeFieldName: undefined, - fromDate: '2022-12-05T23:00:00.000Z', - toDate: '2023-01-05T09:33:05.359Z', - }) - ).toBeNull(); - }); - }); - - describe('fetchAndCalculateFieldStats()', () => { - it('should provide top values', async () => { - const searchHandler = jest.fn().mockResolvedValue({ - values: [ - [3, 'a'], - [1, 'b'], - ], - }); - expect( - await fetchAndCalculateFieldStats({ - searchHandler, - esqlBaseQuery: 'from logs* | limit 1000', - field: { name: 'message', type: 'string', esTypes: ['keyword'] } as DataViewField, - }) - ).toMatchInlineSnapshot(` - Object { - "sampledDocuments": 4, - "sampledValues": 4, - "topValues": Object { - "buckets": Array [ - Object { - "count": 3, - "key": "a", - }, - Object { - "count": 1, - "key": "b", - }, - ], - }, - "totalDocuments": 4, - } - `); - expect(searchHandler).toHaveBeenCalledWith( - expect.objectContaining({ - query: - 'from logs* | limit 1000\n| WHERE `message` IS NOT NULL\n | STATS `message_terms` = count(`message`) BY `message`\n | SORT `message_terms` DESC\n | LIMIT 10', - }) - ); - }); - - it('should provide text examples', async () => { - const searchHandler = jest.fn().mockResolvedValue({ - values: [[['programming', 'cool']], ['elastic', 'cool']], - }); - expect( - await fetchAndCalculateFieldStats({ - searchHandler, - esqlBaseQuery: 'from logs* | limit 1000', - field: { name: 'message', type: 'string', esTypes: ['text'] } as DataViewField, - }) - ).toMatchInlineSnapshot(` - Object { - "sampledDocuments": 2, - "sampledValues": 4, - "topValues": Object { - "areExamples": true, - "buckets": Array [ - Object { - "count": 2, - "key": "cool", - }, - Object { - "count": 1, - "key": "elastic", - }, - Object { - "count": 1, - "key": "programming", - }, - ], - }, - "totalDocuments": 2, - } - `); - - expect(searchHandler).toHaveBeenCalledWith( - expect.objectContaining({ - query: - 'from logs* | limit 1000\n| WHERE `message` IS NOT NULL\n | KEEP `message`\n | LIMIT 100', - }) - ); - }); - }); -}); diff --git a/packages/kbn-unified-field-list/src/services/field_stats_text_based/field_stats_utils_text_based.ts b/packages/kbn-unified-field-list/src/services/field_stats_text_based/field_stats_utils_text_based.ts deleted file mode 100644 index b64d26b0cbb5..000000000000 --- a/packages/kbn-unified-field-list/src/services/field_stats_text_based/field_stats_utils_text_based.ts +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", 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 { ESQLSearchResponse } from '@kbn/es-types'; -import { appendToESQLQuery } from '@kbn/esql-utils'; -import type { DataViewField } from '@kbn/data-views-plugin/common'; -import type { FieldStatsResponse } from '../../types'; -import { - DEFAULT_TOP_VALUES_SIZE, - DEFAULT_SIMPLE_EXAMPLES_SIZE, - SIMPLE_EXAMPLES_FETCH_SIZE, -} from '../../constants'; -import { - canProvideStatsForFieldTextBased, - canProvideTopValuesForFieldTextBased, - canProvideExamplesForField, -} from '../../utils/can_provide_stats'; -import { getFieldExampleBuckets } from '../field_examples_calculator'; - -export type SearchHandlerTextBased = ({ query }: { query: string }) => Promise; - -export function buildSearchFilter({ - timeFieldName, - fromDate, - toDate, -}: { - timeFieldName?: string; - fromDate: string; - toDate: string; -}) { - return timeFieldName - ? { - range: { - [timeFieldName]: { - gte: fromDate, - lte: toDate, - format: 'strict_date_optional_time', - }, - }, - } - : null; -} - -interface FetchAndCalculateFieldStatsParams { - searchHandler: SearchHandlerTextBased; - field: DataViewField; - esqlBaseQuery: string; -} - -export async function fetchAndCalculateFieldStats(params: FetchAndCalculateFieldStatsParams) { - const { field } = params; - if (!canProvideStatsForFieldTextBased(field)) { - return {}; - } - if (field.type === 'boolean') { - return await getStringTopValues(params, 3); - } - if (canProvideTopValuesForFieldTextBased(field)) { - return await getStringTopValues(params); - } - if (canProvideExamplesForField(field, true)) { - return await getSimpleTextExamples(params); - } - - return {}; -} - -export async function getStringTopValues( - params: FetchAndCalculateFieldStatsParams, - size = DEFAULT_TOP_VALUES_SIZE -): Promise> { - const { searchHandler, field, esqlBaseQuery } = params; - const safeEsqlFieldName = getSafeESQLFieldName(field.name); - const safeEsqlFieldNameTerms = getSafeESQLFieldName(`${field.name}_terms`); - const esqlQuery = appendToESQLQuery( - esqlBaseQuery, - `| WHERE ${safeEsqlFieldName} IS NOT NULL - | STATS ${safeEsqlFieldNameTerms} = count(${safeEsqlFieldName}) BY ${safeEsqlFieldName} - | SORT ${safeEsqlFieldNameTerms} DESC - | LIMIT ${size}` - ); - - const result = await searchHandler({ query: esqlQuery }); - const values = result?.values as Array<[number, string]>; - - if (!values?.length) { - return {}; - } - - const sampledValues = values?.reduce((acc: number, row) => acc + row[0], 0); - - const topValues = { - buckets: values.map((value) => ({ - count: value[0], - key: value[1], - })), - }; - - return { - totalDocuments: sampledValues, - sampledDocuments: sampledValues, - sampledValues, - topValues, - }; -} - -export async function getSimpleTextExamples( - params: FetchAndCalculateFieldStatsParams -): Promise> { - const { searchHandler, field, esqlBaseQuery } = params; - const safeEsqlFieldName = getSafeESQLFieldName(field.name); - const esqlQuery = appendToESQLQuery( - esqlBaseQuery, - `| WHERE ${safeEsqlFieldName} IS NOT NULL - | KEEP ${safeEsqlFieldName} - | LIMIT ${SIMPLE_EXAMPLES_FETCH_SIZE}` - ); - - const result = await searchHandler({ query: esqlQuery }); - const values = ((result?.values as Array<[string | string[]]>) || []).map((value) => - Array.isArray(value) && value.length === 1 ? value[0] : value - ); - - if (!values?.length) { - return {}; - } - - const sampledDocuments = values?.length; - - const fieldExampleBuckets = getFieldExampleBuckets({ - values, - field, - count: DEFAULT_SIMPLE_EXAMPLES_SIZE, - isTextBased: true, - }); - - return { - totalDocuments: sampledDocuments, - sampledDocuments: fieldExampleBuckets.sampledDocuments, - sampledValues: fieldExampleBuckets.sampledValues, - topValues: { - buckets: fieldExampleBuckets.buckets, - areExamples: true, - }, - }; -} - -function getSafeESQLFieldName(str: string): string { - return `\`${str}\``; -} diff --git a/packages/kbn-unified-field-list/src/services/field_stats_text_based/load_field_stats_text_based.ts b/packages/kbn-unified-field-list/src/services/field_stats_text_based/load_field_stats_text_based.ts deleted file mode 100644 index 5f77f1590689..000000000000 --- a/packages/kbn-unified-field-list/src/services/field_stats_text_based/load_field_stats_text_based.ts +++ /dev/null @@ -1,89 +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 type { DataView, DataViewField } from '@kbn/data-views-plugin/common'; -import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; -import type { AggregateQuery } from '@kbn/es-query'; -import { getESQLWithSafeLimit, getESQLResults } from '@kbn/esql-utils'; -import type { FieldStatsResponse } from '../../types'; -import { - buildSearchFilter, - SearchHandlerTextBased, - fetchAndCalculateFieldStats, -} from './field_stats_utils_text_based'; -import { ESQL_SAFE_LIMIT } from '../../constants'; - -interface FetchFieldStatsParamsTextBased { - services: { - data: DataPublicPluginStart; - }; - dataView: DataView; - field: DataViewField; - fromDate: string; - toDate: string; - baseQuery: AggregateQuery; - abortController?: AbortController; -} - -export type LoadFieldStatsTextBasedHandler = ( - params: FetchFieldStatsParamsTextBased -) => Promise>; - -/** - * Loads and aggregates stats data for an ES|QL query field - * @param services - * @param dataView - * @param field - * @param fromDate - * @param toDate - * @param baseQuery - * @param abortController - */ -export const loadFieldStatsTextBased: LoadFieldStatsTextBasedHandler = async ({ - services, - dataView, - field, - fromDate, - toDate, - baseQuery, - abortController, -}) => { - const { data } = services; - - try { - if (!dataView?.id || !field?.type) { - return {}; - } - - const searchHandler: SearchHandlerTextBased = async ({ query }) => { - const filter = buildSearchFilter({ timeFieldName: dataView.timeFieldName, fromDate, toDate }); - const result = await getESQLResults({ - esqlQuery: query, - filter, - search: data.search.search, - signal: abortController?.signal, - timeRange: { from: fromDate, to: toDate }, - }); - return result.response; - }; - - if (!('esql' in baseQuery)) { - throw new Error('query must be of type AggregateQuery'); - } - - return await fetchAndCalculateFieldStats({ - searchHandler, - field, - esqlBaseQuery: getESQLWithSafeLimit(baseQuery.esql, ESQL_SAFE_LIMIT), - }); - } catch (error) { - // console.error(error); - throw new Error('Could not provide field stats', { cause: error }); - } -}; diff --git a/packages/kbn-unified-field-list/src/utils/can_provide_stats.test.ts b/packages/kbn-unified-field-list/src/utils/can_provide_stats.test.ts index 297e1e26c8c5..c27a44494a3e 100644 --- a/packages/kbn-unified-field-list/src/utils/can_provide_stats.test.ts +++ b/packages/kbn-unified-field-list/src/utils/can_provide_stats.test.ts @@ -10,7 +10,7 @@ import { canProvideStatsForField, canProvideExamplesForField, - canProvideStatsForFieldTextBased, + canProvideStatsForEsqlField, } from './can_provide_stats'; import type { DataViewField } from '@kbn/data-views-plugin/common'; import { stubLogstashDataView as dataView } from '@kbn/data-views-plugin/common/data_view.stub'; @@ -34,40 +34,12 @@ describe('can_provide_stats', function () { ); }); - it('works for text based columns', function () { + it('should not work for ES|QL columns', function () { expect( canProvideStatsForField( { name: 'message', type: 'string', esTypes: ['text'] } as DataViewField, true ) - ).toBe(true); - expect( - canProvideStatsForField( - { name: 'message', type: 'string', esTypes: ['keyword'] } as DataViewField, - true - ) - ).toBe(true); - expect( - canProvideStatsForField({ name: 'message', type: 'number' } as DataViewField, true) - ).toBe(true); - expect( - canProvideStatsForField({ name: 'message', type: 'boolean' } as DataViewField, true) - ).toBe(true); - expect(canProvideStatsForField({ name: 'message', type: 'ip' } as DataViewField, true)).toBe( - true - ); - expect( - canProvideStatsForField({ name: 'message', type: 'geo_point' } as DataViewField, true) - ).toBe(true); - expect( - canProvideStatsForField( - { name: '_id', type: 'string', esTypes: ['keyword'] } as DataViewField, - true - ) - ).toBe(true); - - expect( - canProvideStatsForField({ name: 'message', type: 'date' } as DataViewField, true) ).toBe(false); }); }); @@ -82,83 +54,24 @@ describe('can_provide_stats', function () { ); }); - it('works for text based columns', function () { + it('should not work for ES|QL columns', function () { expect( canProvideExamplesForField( { name: 'message', type: 'string', esTypes: ['text'] } as DataViewField, true ) - ).toBe(true); - expect( - canProvideExamplesForField( - { name: 'message', type: 'string', esTypes: ['keyword'] } as DataViewField, - true - ) - ).toBe(false); - expect( - canProvideExamplesForField({ name: 'message', type: 'number' } as DataViewField, true) - ).toBe(false); - expect( - canProvideExamplesForField({ name: 'message', type: 'boolean' } as DataViewField, true) ).toBe(false); - expect( - canProvideExamplesForField({ name: 'message', type: 'ip' } as DataViewField, true) - ).toBe(false); - expect( - canProvideExamplesForField({ name: 'message', type: 'geo_point' } as DataViewField, true) - ).toBe(true); - expect( - canProvideExamplesForField({ name: 'message', type: 'date' } as DataViewField, true) - ).toBe(false); - expect( - canProvideStatsForField( - { name: '_id', type: 'string', esTypes: ['keyword'] } as DataViewField, - true - ) - ).toBe(true); }); - describe('canProvideStatsForFieldTextBased', function () { - it('works for text based columns', function () { + describe('canProvideStatsForEsqlField', function () { + it('should not work for ES|QL columns', function () { expect( - canProvideStatsForFieldTextBased({ + canProvideStatsForEsqlField({ name: 'message', type: 'string', esTypes: ['text'], } as DataViewField) - ).toBe(true); - expect( - canProvideStatsForFieldTextBased({ - name: 'message', - type: 'string', - esTypes: ['keyword'], - } as DataViewField) - ).toBe(true); - expect( - canProvideStatsForFieldTextBased({ name: 'message', type: 'number' } as DataViewField) - ).toBe(true); - expect( - canProvideStatsForFieldTextBased({ name: 'message', type: 'boolean' } as DataViewField) - ).toBe(true); - expect( - canProvideStatsForFieldTextBased({ name: 'message', type: 'ip' } as DataViewField) - ).toBe(true); - expect( - canProvideStatsForFieldTextBased({ name: 'message', type: 'ip_range' } as DataViewField) ).toBe(false); - expect( - canProvideStatsForFieldTextBased({ name: 'message', type: 'geo_point' } as DataViewField) - ).toBe(true); - expect( - canProvideStatsForFieldTextBased({ name: 'message', type: 'date' } as DataViewField) - ).toBe(false); - expect( - canProvideStatsForFieldTextBased({ - name: '_id', - type: 'string', - esTypes: ['keyword'], - } as DataViewField) - ).toBe(true); }); }); }); diff --git a/packages/kbn-unified-field-list/src/utils/can_provide_stats.ts b/packages/kbn-unified-field-list/src/utils/can_provide_stats.ts index e84137fa17f2..c3fd9734de5e 100644 --- a/packages/kbn-unified-field-list/src/utils/can_provide_stats.ts +++ b/packages/kbn-unified-field-list/src/utils/can_provide_stats.ts @@ -9,22 +9,22 @@ import type { DataViewField } from '@kbn/data-views-plugin/common'; -export function canProvideStatsForField(field: DataViewField, isTextBased: boolean): boolean { - if (isTextBased) { - return canProvideStatsForFieldTextBased(field); +export function canProvideStatsForField(field: DataViewField, isEsqlQuery: boolean): boolean { + if (isEsqlQuery) { + return false; } return ( - (field.aggregatable && canProvideAggregatedStatsForField(field, isTextBased)) || + (field.aggregatable && canProvideAggregatedStatsForField(field, isEsqlQuery)) || ((!field.aggregatable || field.type === 'geo_point' || field.type === 'geo_shape') && - canProvideExamplesForField(field, isTextBased)) + canProvideExamplesForField(field, isEsqlQuery)) ); } export function canProvideAggregatedStatsForField( field: DataViewField, - isTextBased: boolean + isEsqlQuery: boolean ): boolean { - if (isTextBased) { + if (isEsqlQuery) { return false; } return !( @@ -39,20 +39,17 @@ export function canProvideAggregatedStatsForField( export function canProvideNumberSummaryForField( field: DataViewField, - isTextBased: boolean + isEsqlQuery: boolean ): boolean { - if (isTextBased) { + if (isEsqlQuery) { return false; } return field.timeSeriesMetric === 'counter'; } -export function canProvideExamplesForField(field: DataViewField, isTextBased: boolean): boolean { - if (isTextBased) { - return ( - (field.type === 'string' && !canProvideTopValuesForFieldTextBased(field)) || - ['geo_point', 'geo_shape'].includes(field.type) - ); +export function canProvideExamplesForField(field: DataViewField, isEsqlQuery: boolean): boolean { + if (isEsqlQuery) { + return false; } if (field.name === '_score') { return false; @@ -69,17 +66,6 @@ export function canProvideExamplesForField(field: DataViewField, isTextBased: bo ].includes(field.type); } -export function canProvideTopValuesForFieldTextBased(field: DataViewField): boolean { - if (field.name === '_id') { - return false; - } - const esTypes = field.esTypes?.[0]; - return ( - Boolean(field.type === 'string' && esTypes && ['keyword', 'version'].includes(esTypes)) || - ['keyword', 'version', 'ip', 'number', 'boolean'].includes(field.type) - ); -} - -export function canProvideStatsForFieldTextBased(field: DataViewField): boolean { - return canProvideTopValuesForFieldTextBased(field) || canProvideExamplesForField(field, true); +export function canProvideStatsForEsqlField(field: DataViewField): boolean { + return false; } diff --git a/packages/kbn-unified-field-list/tsconfig.json b/packages/kbn-unified-field-list/tsconfig.json index 830e56ac6ab0..630ce0540ee1 100644 --- a/packages/kbn-unified-field-list/tsconfig.json +++ b/packages/kbn-unified-field-list/tsconfig.json @@ -32,10 +32,10 @@ "@kbn/shared-ux-button-toolbar", "@kbn/field-utils", "@kbn/visualization-utils", - "@kbn/esql-utils", "@kbn/search-types", "@kbn/fields-metadata-plugin", - "@kbn/ui-theme" + "@kbn/ui-theme", + "@kbn/esql-utils", ], "exclude": ["target/**/*"] } diff --git a/packages/shared-ux/page/kibana_template/impl/src/__snapshots__/page_template.test.tsx.snap b/packages/shared-ux/page/kibana_template/impl/src/__snapshots__/page_template.test.tsx.snap index f455fbb1d00b..78bccf0fef07 100644 --- a/packages/shared-ux/page/kibana_template/impl/src/__snapshots__/page_template.test.tsx.snap +++ b/packages/shared-ux/page/kibana_template/impl/src/__snapshots__/page_template.test.tsx.snap @@ -35,7 +35,7 @@ exports[`KibanaPageTemplate render basic template 1`] = ` class="euiFlexGroup emotion-euiFlexGroup-wrap-l-flexStart-stretch-row-euiPageHeaderContent__rightSideItems" >
    test
    diff --git a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts index f31ec223e3d9..02f7007b5120 100644 --- a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts +++ b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts @@ -73,7 +73,7 @@ describe('checking migration metadata changes on all registered SO types', () => "canvas-element": "cdedc2123eb8a1506b87a56b0bcce60f4ec08bc8", "canvas-workpad": "9d82aafb19586b119e5c9382f938abe28c26ca5c", "canvas-workpad-template": "c077b0087346776bb3542b51e1385d172cb24179", - "cases": "2392189ed338857d4815a4cef6051f9ad124d39d", + "cases": "5433a9f1277f8f17bbc4fd20d33b1fc6d997931e", "cases-comments": "5cb0a421588831c2a950e50f486048b8aabbae25", "cases-configure": "44ed7b8e0f44df39516b8870589b89e32224d2bf", "cases-connector-mappings": "f9d1ac57e484e69506c36a8051e4d61f4a8cfd25", @@ -122,7 +122,7 @@ describe('checking migration metadata changes on all registered SO types', () => "infrastructure-ui-source": "113182d6895764378dfe7fa9fa027244f3a457c4", "ingest-agent-policies": "5e95e539826a40ad08fd0c1d161da0a4d86ffc6d", "ingest-download-sources": "279a68147e62e4d8858c09ad1cf03bd5551ce58d", - "ingest-outputs": "daafff49255ab700e07491376fe89f04fc998b91", + "ingest-outputs": "55988d5f778bbe0e76caa7e6468707a0a056bdd8", "ingest-package-policies": "53a94064674835fdb35e5186233bcd7052eabd22", "ingest_manager_settings": "111a616eb72627c002029c19feb9e6c439a10505", "inventory-view": "b8683c8e352a286b4aca1ab21003115a4800af83", @@ -165,6 +165,7 @@ describe('checking migration metadata changes on all registered SO types', () => "synthetics-dynamic-settings": "4b40a93eb3e222619bf4e7fe34a9b9e7ab91a0a7", "synthetics-monitor": "5ceb25b6249bd26902c9b34273c71c3dce06dbea", "synthetics-param": "3ebb744e5571de678b1312d5c418c8188002cf5e", + "synthetics-private-location": "8cecc9e4f39637d2f8244eb7985c0690ceab24be", "synthetics-privates-locations": "f53d799d5c9bc8454aaa32c6abc99a899b025d5c", "tag": "e2544392fe6563e215bb677abc8b01c2601ef2dc", "task": "3c89a7c918d5b896a5f8800f06e9114ad7e7aea3", diff --git a/src/core/server/integration_tests/http/logging.test.ts b/src/core/server/integration_tests/http/logging.test.ts index 795424a7d30d..54b157c291a4 100644 --- a/src/core/server/integration_tests/http/logging.test.ts +++ b/src/core/server/integration_tests/http/logging.test.ts @@ -28,11 +28,28 @@ describe('request logging', () => { describe('http server response logging', () => { describe('configuration', () => { + let root: ReturnType; + + afterEach(async () => { + await root?.shutdown(); + }); it('does not log with a default config', async () => { - const root = createRoot({ + root = createRoot({ plugins: { initialize: false }, elasticsearch: { skipStartupConnectionCheck: true }, server: { restrictInternalApis: false }, + logging: { + appenders: { + 'test-console': { type: 'console', layout: { type: 'json' } }, + }, + loggers: [ + { + name: 'http.server.response', + appenders: ['test-console'], + level: 'off', + }, + ], + }, }); await root.preboot(); const { http } = await root.setup(); @@ -47,12 +64,10 @@ describe('request logging', () => { await request.get(root, '/ping').expect(200, 'pong'); expect(mockConsoleLog).not.toHaveBeenCalled(); - - await root.shutdown(); }); it('logs at the correct level and with the correct context', async () => { - const root = createRoot({ + root = createRoot({ logging: { appenders: { 'test-console': { @@ -93,8 +108,6 @@ describe('request logging', () => { const [level, logger] = mockConsoleLog.mock.calls[0][0].split('|'); expect(level).toBe('DEBUG'); expect(logger).toBe('http.server.response'); - - await root.shutdown(); }); }); @@ -131,7 +144,7 @@ describe('request logging', () => { }); afterEach(async () => { - await root.shutdown(); + await root?.shutdown(); }); it('handles a GET request', async () => { diff --git a/src/core/server/integration_tests/node/logging.test.ts b/src/core/server/integration_tests/node/logging.test.ts index b505939aef59..5b200a9890b7 100644 --- a/src/core/server/integration_tests/node/logging.test.ts +++ b/src/core/server/integration_tests/node/logging.test.ts @@ -16,6 +16,13 @@ function createRootWithRoles(roles: string[]) { roles, }, logging: { + loggers: [ + { + name: 'root', + appenders: ['test-console'], + level: 'info', + }, + ], appenders: { 'test-console': { type: 'console', diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/type_registrations.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/type_registrations.test.ts index e95a82e63d0f..ba06073e454a 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group3/type_registrations.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/type_registrations.test.ts @@ -139,6 +139,7 @@ const previouslyRegisteredTypes = [ 'synthetics-monitor', 'synthetics-param', 'synthetics-privates-locations', + 'synthetics-private-location', 'tag', 'task', 'telemetry', diff --git a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_create.test.ts b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_create.test.ts index 8d4028080637..e824e5124f6c 100644 --- a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_create.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_create.test.ts @@ -21,7 +21,7 @@ import { } from '@kbn/core-saved-objects-server-internal'; import { createHiddenTypeVariants, setupServer } from '@kbn/core-test-helpers-test-utils'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from '../routes_test_utils'; +import { deprecationMock, setupConfig } from '../routes_test_utils'; type SetupServerReturn = Awaited>; @@ -56,7 +56,14 @@ describe('POST /api/saved_objects/_bulk_create with allowApiAccess true', () => const logger = loggerMock.create(); const config = setupConfig(true); const access = 'public'; - registerBulkCreateRoute(router, { config, coreUsageData, logger, access }); + + registerBulkCreateRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_delete.test.ts b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_delete.test.ts index 26a2d22403bc..114b682fa51b 100644 --- a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_delete.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_delete.test.ts @@ -20,7 +20,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from '../routes_test_utils'; +import { deprecationMock, setupConfig } from '../routes_test_utils'; type SetupServerReturn = Awaited>; @@ -61,7 +61,13 @@ describe('POST /api/saved_objects/_bulk_delete with allowApiAccess as true', () const config = setupConfig(true); const access = 'public'; - registerBulkDeleteRoute(router, { config, coreUsageData, logger, access }); + registerBulkDeleteRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_get.test.ts b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_get.test.ts index da491110b071..bd6caca6233c 100644 --- a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_get.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_get.test.ts @@ -20,7 +20,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from '../routes_test_utils'; +import { deprecationMock, setupConfig } from '../routes_test_utils'; type SetupServerReturn = Awaited>; @@ -58,7 +58,14 @@ describe('POST /api/saved_objects/_bulk_get with allowApiAccess true', () => { const config = setupConfig(true); const access = 'public'; - registerBulkGetRoute(router, { config, coreUsageData, logger, access }); + + registerBulkGetRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_resolve.test.ts b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_resolve.test.ts index 054f55f518a6..f297f1b6a8cb 100644 --- a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_resolve.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_resolve.test.ts @@ -20,7 +20,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from '../routes_test_utils'; +import { deprecationMock, setupConfig } from '../routes_test_utils'; type SetupServerReturn = Awaited>; @@ -59,7 +59,14 @@ describe('POST /api/saved_objects/_bulk_resolve with allowApiAccess true', () => const config = setupConfig(true); const access = 'public'; - registerBulkResolveRoute(router, { config, coreUsageData, logger, access }); + + registerBulkResolveRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_update.test.ts b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_update.test.ts index 275e803f6ceb..7625334bbe63 100644 --- a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_update.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/bulk_update.test.ts @@ -19,7 +19,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from '../routes_test_utils'; +import { deprecationMock, setupConfig } from '../routes_test_utils'; type SetupServerReturn = Awaited>; const testTypes = [ @@ -52,7 +52,14 @@ describe('PUT /api/saved_objects/_bulk_update with allowApiAccess true', () => { const config = setupConfig(true); const access = 'public'; - registerBulkUpdateRoute(router, { config, coreUsageData, logger, access }); + + registerBulkUpdateRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/create.test.ts b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/create.test.ts index 478c23346672..632b41fe886b 100644 --- a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/create.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/create.test.ts @@ -20,7 +20,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from '../routes_test_utils'; +import { deprecationMock, setupConfig } from '../routes_test_utils'; type SetupServerReturn = Awaited>; @@ -58,7 +58,14 @@ describe('POST /api/saved_objects/{type} with allowApiAccess true', () => { const logger = loggerMock.create(); const config = setupConfig(true); const access = 'public'; - registerCreateRoute(router, { config, coreUsageData, logger, access }); + + registerCreateRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); handlerContext.savedObjects.typeRegistry.getType.mockImplementation((typename: string) => { return testTypes diff --git a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/delete.test.ts b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/delete.test.ts index 83cb90ab4d8d..a1f3ff0bc60e 100644 --- a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/delete.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/delete.test.ts @@ -20,7 +20,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from '../routes_test_utils'; +import { deprecationMock, setupConfig } from '../routes_test_utils'; type SetupServerReturn = Awaited>; @@ -55,7 +55,14 @@ describe('DELETE /api/saved_objects/{type}/{id} with allowApiAccess true', () => const logger = loggerMock.create(); const config = setupConfig(true); const access = 'public'; - registerDeleteRoute(router, { config, coreUsageData, logger, access }); + + registerDeleteRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/find.test.ts b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/find.test.ts index 3f7e0b815662..c87546ea4887 100644 --- a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/find.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/find.test.ts @@ -21,7 +21,7 @@ import { registerFindRoute, type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; -import { setupConfig } from '../routes_test_utils'; +import { deprecationMock, setupConfig } from '../routes_test_utils'; type SetupServerReturn = Awaited>; @@ -72,7 +72,13 @@ describe('GET /api/saved_objects/_find with allowApiAccess true', () => { const config = setupConfig(true); const access = 'public'; - registerFindRoute(router, { config, coreUsageData, logger, access }); + registerFindRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/get.test.ts b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/get.test.ts index c97ae350c038..6220de654068 100644 --- a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/get.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/get.test.ts @@ -25,7 +25,7 @@ import { } from '@kbn/core-saved-objects-server-internal'; import { createHiddenTypeVariants } from '@kbn/core-test-helpers-test-utils'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from '../routes_test_utils'; +import { deprecationMock, setupConfig } from '../routes_test_utils'; const coreId = Symbol('core'); const testTypes = [ @@ -80,7 +80,14 @@ describe('GET /api/saved_objects/{type}/{id} with allowApiAccess true', () => { const config = setupConfig(true); const access = 'public'; - registerGetRoute(router, { config, coreUsageData, logger, access }); + + registerGetRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/resolve.test.ts b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/resolve.test.ts index bc00a418a13b..f1f7fd1d6153 100644 --- a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/resolve.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/resolve.test.ts @@ -25,7 +25,7 @@ import { } from '@kbn/core-saved-objects-server-internal'; import { createHiddenTypeVariants } from '@kbn/core-test-helpers-test-utils'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from '../routes_test_utils'; +import { deprecationMock, setupConfig } from '../routes_test_utils'; const coreId = Symbol('core'); @@ -81,7 +81,13 @@ describe('GET /api/saved_objects/resolve/{type}/{id} with allowApiAccess true', const config = setupConfig(true); const access = 'public'; - registerResolveRoute(router, { config, coreUsageData, logger, access }); + registerResolveRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/update.test.ts b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/update.test.ts index 25da93b52628..2a086f29d75d 100644 --- a/src/core/server/integration_tests/saved_objects/routes/allow_api_access/update.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/allow_api_access/update.test.ts @@ -20,7 +20,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from '../routes_test_utils'; +import { deprecationMock, setupConfig } from '../routes_test_utils'; type SetupServerReturn = Awaited>; @@ -56,7 +56,14 @@ describe('PUT /api/saved_objects/{type}/{id?} with allowApiAccess true', () => { const config = setupConfig(true); const access = 'public'; - registerUpdateRoute(router, { config, coreUsageData, logger, access }); + + registerUpdateRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/bulk_create.test.ts b/src/core/server/integration_tests/saved_objects/routes/bulk_create.test.ts index 3eaf3bbdc886..033a5570c588 100644 --- a/src/core/server/integration_tests/saved_objects/routes/bulk_create.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/bulk_create.test.ts @@ -21,7 +21,7 @@ import { } from '@kbn/core-saved-objects-server-internal'; import { createHiddenTypeVariants, setupServer } from '@kbn/core-test-helpers-test-utils'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from './routes_test_utils'; +import { deprecationMock, setupConfig } from './routes_test_utils'; type SetupServerReturn = Awaited>; @@ -37,6 +37,7 @@ describe('POST /api/saved_objects/_bulk_create', () => { let savedObjectsClient: ReturnType; let coreUsageStatsClient: jest.Mocked; let loggerWarnSpy: jest.SpyInstance; + let registrationSpy: jest.SpyInstance; beforeEach(async () => { ({ server, httpSetup, handlerContext } = await setupServer()); @@ -57,11 +58,18 @@ describe('POST /api/saved_objects/_bulk_create', () => { const logger = loggerMock.create(); loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation(); + registrationSpy = jest.spyOn(router, 'post'); const config = setupConfig(); const access = 'public'; - registerBulkCreateRoute(router, { config, coreUsageData, logger, access }); + registerBulkCreateRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); @@ -194,4 +202,24 @@ describe('POST /api/saved_objects/_bulk_create', () => { .expect(200); expect(loggerWarnSpy).toHaveBeenCalledTimes(1); }); + + it('passes deprecation config to the router arguments', async () => { + await supertest(httpSetup.server.listener) + .post('/api/saved_objects/_bulk_create') + .set('x-elastic-internal-origin', 'kibana') + .send([ + { + id: 'abc1234', + type: 'index-pattern', + attributes: { + title: 'foo', + }, + references: [], + }, + ]) + .expect(200); + expect(registrationSpy.mock.calls[0][0]).toMatchObject({ + options: { deprecated: deprecationMock }, + }); + }); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/bulk_delete.test.ts b/src/core/server/integration_tests/saved_objects/routes/bulk_delete.test.ts index 24f2cf29fe14..9421d5207b21 100644 --- a/src/core/server/integration_tests/saved_objects/routes/bulk_delete.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/bulk_delete.test.ts @@ -20,7 +20,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from './routes_test_utils'; +import { deprecationMock, setupConfig } from './routes_test_utils'; type SetupServerReturn = Awaited>; @@ -36,6 +36,7 @@ describe('POST /api/saved_objects/_bulk_delete', () => { let savedObjectsClient: ReturnType; let coreUsageStatsClient: jest.Mocked; let loggerWarnSpy: jest.SpyInstance; + let registrationSpy: jest.SpyInstance; beforeEach(async () => { ({ server, httpSetup, handlerContext } = await setupServer()); @@ -59,11 +60,18 @@ describe('POST /api/saved_objects/_bulk_delete', () => { const logger = loggerMock.create(); loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation(); + registrationSpy = jest.spyOn(router, 'post'); const config = setupConfig(); const access = 'public'; - registerBulkDeleteRoute(router, { config, coreUsageData, logger, access }); + registerBulkDeleteRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); @@ -163,4 +171,21 @@ describe('POST /api/saved_objects/_bulk_delete', () => { .expect(400); expect(loggerWarnSpy).toHaveBeenCalledTimes(1); }); + + it('passes deprecation configuration to the router arguments', async () => { + await supertest(httpSetup.server.listener) + .post('/api/saved_objects/_bulk_delete') + .set('x-elastic-internal-origin', 'kibana') + .send([ + { + id: 'hiddenID', + type: 'hidden-from-http', + }, + ]) + .expect(400); + + expect(registrationSpy.mock.calls[0][0]).toMatchObject({ + options: { deprecated: deprecationMock }, + }); + }); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/bulk_get.test.ts b/src/core/server/integration_tests/saved_objects/routes/bulk_get.test.ts index 519bdbb5f6c7..8d16ca578735 100644 --- a/src/core/server/integration_tests/saved_objects/routes/bulk_get.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/bulk_get.test.ts @@ -20,7 +20,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from './routes_test_utils'; +import { deprecationMock, setupConfig } from './routes_test_utils'; type SetupServerReturn = Awaited>; @@ -36,6 +36,7 @@ describe('POST /api/saved_objects/_bulk_get', () => { let savedObjectsClient: ReturnType; let coreUsageStatsClient: jest.Mocked; let loggerWarnSpy: jest.SpyInstance; + let registrationSpy: jest.SpyInstance; beforeEach(async () => { ({ server, httpSetup, handlerContext } = await setupServer()); @@ -57,11 +58,18 @@ describe('POST /api/saved_objects/_bulk_get', () => { const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient); const logger = loggerMock.create(); loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation(); + registrationSpy = jest.spyOn(router, 'post'); const config = setupConfig(); const access = 'public'; - registerBulkGetRoute(router, { config, coreUsageData, logger, access }); + registerBulkGetRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); @@ -150,4 +158,20 @@ describe('POST /api/saved_objects/_bulk_get', () => { .expect(200); expect(loggerWarnSpy).toHaveBeenCalledTimes(1); }); + + it('passes deprecation config to the router arguments', async () => { + await supertest(httpSetup.server.listener) + .post('/api/saved_objects/_bulk_get') + .set('x-elastic-internal-origin', 'kibana') + .send([ + { + id: 'abc123', + type: 'index-pattern', + }, + ]) + .expect(200); + expect(registrationSpy.mock.calls[0][0]).toMatchObject({ + options: { deprecated: deprecationMock }, + }); + }); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/bulk_resolve.test.ts b/src/core/server/integration_tests/saved_objects/routes/bulk_resolve.test.ts index 2636d38fc28b..800fccb00324 100644 --- a/src/core/server/integration_tests/saved_objects/routes/bulk_resolve.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/bulk_resolve.test.ts @@ -20,7 +20,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from './routes_test_utils'; +import { deprecationMock, setupConfig } from './routes_test_utils'; type SetupServerReturn = Awaited>; @@ -36,6 +36,7 @@ describe('POST /api/saved_objects/_bulk_resolve', () => { let savedObjectsClient: ReturnType; let coreUsageStatsClient: jest.Mocked; let loggerWarnSpy: jest.SpyInstance; + let registrationSpy: jest.SpyInstance; beforeEach(async () => { ({ server, httpSetup, handlerContext } = await setupServer()); @@ -58,11 +59,17 @@ describe('POST /api/saved_objects/_bulk_resolve', () => { const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient); const logger = loggerMock.create(); loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation(); + registrationSpy = jest.spyOn(router, 'post'); const config = setupConfig(); const access = 'public'; - - registerBulkResolveRoute(router, { config, coreUsageData, logger, access }); + registerBulkResolveRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); @@ -154,4 +161,20 @@ describe('POST /api/saved_objects/_bulk_resolve', () => { .expect(200); expect(loggerWarnSpy).toHaveBeenCalledTimes(1); }); + + it('passes deprecation configuration to the router arguments', async () => { + await supertest(httpSetup.server.listener) + .post('/api/saved_objects/_bulk_resolve') + .set('x-elastic-internal-origin', 'kibana') + .send([ + { + id: 'abc123', + type: 'index-pattern', + }, + ]) + .expect(200); + expect(registrationSpy.mock.calls[0][0]).toMatchObject({ + options: { deprecated: deprecationMock }, + }); + }); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/bulk_update.test.ts b/src/core/server/integration_tests/saved_objects/routes/bulk_update.test.ts index 8ea206b4d902..d746d1d5b9ca 100644 --- a/src/core/server/integration_tests/saved_objects/routes/bulk_update.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/bulk_update.test.ts @@ -20,7 +20,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from './routes_test_utils'; +import { deprecationMock, setupConfig } from './routes_test_utils'; type SetupServerReturn = Awaited>; const testTypes = [ @@ -37,6 +37,7 @@ describe('PUT /api/saved_objects/_bulk_update', () => { let savedObjectsClient: ReturnType; let coreUsageStatsClient: jest.Mocked; let loggerWarnSpy: jest.SpyInstance; + let registrationSpy: jest.SpyInstance; beforeEach(async () => { ({ server, httpSetup, handlerContext } = await setupServer()); @@ -56,11 +57,18 @@ describe('PUT /api/saved_objects/_bulk_update', () => { const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient); const logger = loggerMock.create(); loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation(); + registrationSpy = jest.spyOn(router, 'put'); const config = setupConfig(); const access = 'public'; - registerBulkUpdateRoute(router, { config, coreUsageData, logger, access }); + registerBulkUpdateRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); @@ -180,6 +188,7 @@ describe('PUT /api/saved_objects/_bulk_update', () => { }, ]) .expect(400); + expect(result.body.message).toContain('Unsupported saved object type(s):'); }); @@ -205,5 +214,35 @@ describe('PUT /api/saved_objects/_bulk_update', () => { ]) .expect(200); expect(loggerWarnSpy).toHaveBeenCalledTimes(1); + expect(registrationSpy.mock.calls[0][0]).toMatchObject({ + options: { deprecated: deprecationMock }, + }); + }); + + it('passes deprecation configuration to the router arguments', async () => { + await supertest(httpSetup.server.listener) + .put('/api/saved_objects/_bulk_update') + .set('x-elastic-internal-origin', 'kibana') + .send([ + { + type: 'visualization', + id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', + attributes: { + title: 'An existing visualization', + }, + }, + { + type: 'dashboard', + id: 'be3733a0-9efe-11e7-acb3-3dab96693fab', + attributes: { + title: 'An existing dashboard', + }, + }, + ]) + .expect(200); + + expect(registrationSpy.mock.calls[0][0]).toMatchObject({ + options: { deprecated: deprecationMock }, + }); }); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/create.test.ts b/src/core/server/integration_tests/saved_objects/routes/create.test.ts index 3fe9f5fcc6f0..f2471e14fc12 100644 --- a/src/core/server/integration_tests/saved_objects/routes/create.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/create.test.ts @@ -20,7 +20,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from './routes_test_utils'; +import { deprecationMock, setupConfig } from './routes_test_utils'; type SetupServerReturn = Awaited>; @@ -36,6 +36,7 @@ describe('POST /api/saved_objects/{type}', () => { let savedObjectsClient: ReturnType; let coreUsageStatsClient: jest.Mocked; let loggerWarnSpy: jest.SpyInstance; + let registrationSpy: jest.SpyInstance; const clientResponse = { id: 'logstash-*', @@ -58,10 +59,18 @@ describe('POST /api/saved_objects/{type}', () => { const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient); const logger = loggerMock.create(); loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation(); + registrationSpy = jest.spyOn(router, 'post'); + const config = setupConfig(); const access = 'public'; - registerCreateRoute(router, { config, coreUsageData, logger, access }); + registerCreateRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); handlerContext.savedObjects.typeRegistry.getType.mockImplementation((typename: string) => { return testTypes @@ -178,4 +187,19 @@ describe('POST /api/saved_objects/{type}', () => { .expect(200); expect(loggerWarnSpy).toHaveBeenCalledTimes(1); }); + + it('passes deprecation configuration to the router arguments', async () => { + await supertest(httpSetup.server.listener) + .post('/api/saved_objects/index-pattern') + .set('x-elastic-internal-origin', 'kibana') + .send({ + attributes: { + title: 'Logging test', + }, + }) + .expect(200); + expect(registrationSpy.mock.calls[0][0]).toMatchObject({ + options: { deprecated: deprecationMock }, + }); + }); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/delete.test.ts b/src/core/server/integration_tests/saved_objects/routes/delete.test.ts index ba5c797469aa..70d811cd9752 100644 --- a/src/core/server/integration_tests/saved_objects/routes/delete.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/delete.test.ts @@ -20,7 +20,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from './routes_test_utils'; +import { deprecationMock, setupConfig } from './routes_test_utils'; type SetupServerReturn = Awaited>; @@ -37,6 +37,7 @@ describe('DELETE /api/saved_objects/{type}/{id}', () => { let savedObjectsClient: ReturnType; let coreUsageStatsClient: jest.Mocked; let loggerWarnSpy: jest.SpyInstance; + let registrationSpy: jest.SpyInstance; beforeEach(async () => { ({ server, httpSetup, handlerContext } = await setupServer()); @@ -55,9 +56,17 @@ describe('DELETE /api/saved_objects/{type}/{id}', () => { const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient); const logger = loggerMock.create(); loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation(); + registrationSpy = jest.spyOn(router, 'delete'); + const config = setupConfig(); const access = 'public'; - registerDeleteRoute(router, { config, coreUsageData, logger, access }); + registerDeleteRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); @@ -120,4 +129,13 @@ describe('DELETE /api/saved_objects/{type}/{id}', () => { .expect(200); expect(loggerWarnSpy).toHaveBeenCalledTimes(1); }); + + it('passes deprecation configuration to the router arguments', async () => { + await supertest(httpSetup.server.listener) + .delete('/api/saved_objects/index-pattern/logstash-*') + .expect(200); + expect(registrationSpy.mock.calls[0][0]).toMatchObject({ + options: { deprecated: deprecationMock }, + }); + }); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/find.test.ts b/src/core/server/integration_tests/saved_objects/routes/find.test.ts index b7d193db4252..d2048ba13b63 100644 --- a/src/core/server/integration_tests/saved_objects/routes/find.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/find.test.ts @@ -22,7 +22,7 @@ import { registerFindRoute, type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; -import { setupConfig } from './routes_test_utils'; +import { deprecationMock, setupConfig } from './routes_test_utils'; type SetupServerReturn = Awaited>; @@ -42,6 +42,7 @@ describe('GET /api/saved_objects/_find', () => { let savedObjectsClient: ReturnType; let coreUsageStatsClient: jest.Mocked; let loggerWarnSpy: jest.SpyInstance; + let registrationSpy: jest.SpyInstance; const clientResponse = { total: 0, @@ -71,11 +72,18 @@ describe('GET /api/saved_objects/_find', () => { const logger = loggerMock.create(); loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation(); + registrationSpy = jest.spyOn(router, 'get'); const config = setupConfig(); const access = 'public'; - registerFindRoute(router, { config, coreUsageData, logger, access }); + registerFindRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); @@ -471,4 +479,14 @@ describe('GET /api/saved_objects/_find', () => { .expect(200); expect(loggerWarnSpy).toHaveBeenCalledTimes(1); }); + + it('passes deprecation configuration to the router arguments', async () => { + await supertest(httpSetup.server.listener) + .get('/api/saved_objects/_find?type=foo&type=bar') + .set('x-elastic-internal-origin', 'kibana') + .expect(200); + expect(registrationSpy.mock.calls[0][0]).toMatchObject({ + options: { deprecated: deprecationMock }, + }); + }); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/get.test.ts b/src/core/server/integration_tests/saved_objects/routes/get.test.ts index 97868b9cc23d..bb748ca478e8 100644 --- a/src/core/server/integration_tests/saved_objects/routes/get.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/get.test.ts @@ -25,7 +25,7 @@ import { } from '@kbn/core-saved-objects-server-internal'; import { createHiddenTypeVariants } from '@kbn/core-test-helpers-test-utils'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from './routes_test_utils'; +import { deprecationMock, setupConfig } from './routes_test_utils'; const coreId = Symbol('core'); const testTypes = [ @@ -41,6 +41,7 @@ describe('GET /api/saved_objects/{type}/{id}', () => { let savedObjectsClient: ReturnType; let coreUsageStatsClient: jest.Mocked; let loggerWarnSpy: jest.SpyInstance; + let registrationSpy: jest.SpyInstance; beforeEach(async () => { const coreContext = createCoreContext({ coreId }); @@ -80,10 +81,18 @@ describe('GET /api/saved_objects/{type}/{id}', () => { const logger = loggerMock.create(); loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation(); + registrationSpy = jest.spyOn(router, 'get'); + const config = setupConfig(); const access = 'public'; - registerGetRoute(router, { config, coreUsageData, logger, access }); + registerGetRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); @@ -144,4 +153,14 @@ describe('GET /api/saved_objects/{type}/{id}', () => { .expect(200); expect(loggerWarnSpy).toHaveBeenCalledTimes(1); }); + + it('passes deprecation configuration to the router arguments', async () => { + await supertest(httpSetup.server.listener) + .get('/api/saved_objects/index-pattern/logstash-*') + .set('x-elastic-internal-origin', 'kibana') + .expect(200); + expect(registrationSpy.mock.calls[0][0]).toMatchObject({ + options: { deprecated: deprecationMock }, + }); + }); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/legacy_import_export/export.test.ts b/src/core/server/integration_tests/saved_objects/routes/legacy_import_export/export.test.ts index 008ad527e03e..73f1ce075272 100644 --- a/src/core/server/integration_tests/saved_objects/routes/legacy_import_export/export.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/legacy_import_export/export.test.ts @@ -41,6 +41,7 @@ import { registerLegacyExportRoute, type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; +import { legacyDeprecationMock } from '../routes_test_utils'; type SetupServerReturn = Awaited>; let coreUsageStatsClient: jest.Mocked; @@ -58,11 +59,13 @@ describe('POST /api/dashboards/export', () => { coreUsageStatsClient = coreUsageStatsClientMock.create(); coreUsageStatsClient.incrementLegacyDashboardsExport.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient); + registerLegacyExportRoute(router, { kibanaVersion: 'mockversion', coreUsageData, logger: loggerMock.create(), access: 'public', + legacyDeprecationInfo: legacyDeprecationMock, }); handlerContext.savedObjects.client.bulkGet diff --git a/src/core/server/integration_tests/saved_objects/routes/legacy_import_export/import.test.ts b/src/core/server/integration_tests/saved_objects/routes/legacy_import_export/import.test.ts index 0355ac7d3970..c96c0e1d9011 100644 --- a/src/core/server/integration_tests/saved_objects/routes/legacy_import_export/import.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/legacy_import_export/import.test.ts @@ -41,6 +41,7 @@ import { registerLegacyImportRoute, type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; +import { legacyDeprecationMock } from '../routes_test_utils'; type SetupServerReturn = Awaited>; let coreUsageStatsClient: jest.Mocked; @@ -58,11 +59,13 @@ describe('POST /api/dashboards/import', () => { coreUsageStatsClient = coreUsageStatsClientMock.create(); coreUsageStatsClient.incrementLegacyDashboardsImport.mockRejectedValue(new Error('Oh no!')); // intentionally throw this error, which is swallowed, so we can assert that the operation does not fail const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient); + registerLegacyImportRoute(router, { maxImportPayloadBytes: 26214400, coreUsageData, logger: loggerMock.create(), access: 'public', + legacyDeprecationInfo: legacyDeprecationMock, }); handlerContext.savedObjects.client.bulkCreate.mockResolvedValueOnce({ diff --git a/src/core/server/integration_tests/saved_objects/routes/resolve.test.ts b/src/core/server/integration_tests/saved_objects/routes/resolve.test.ts index e96c7ee9fb08..7812081e5329 100644 --- a/src/core/server/integration_tests/saved_objects/routes/resolve.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/resolve.test.ts @@ -25,7 +25,7 @@ import { } from '@kbn/core-saved-objects-server-internal'; import { createHiddenTypeVariants } from '@kbn/core-test-helpers-test-utils'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from './routes_test_utils'; +import { deprecationMock, setupConfig } from './routes_test_utils'; const coreId = Symbol('core'); @@ -42,6 +42,7 @@ describe('GET /api/saved_objects/resolve/{type}/{id}', () => { let savedObjectsClient: ReturnType; let coreUsageStatsClient: jest.Mocked; let loggerWarnSpy: jest.SpyInstance; + let registrationSpy: jest.SpyInstance; beforeEach(async () => { const coreContext = createCoreContext({ coreId }); @@ -79,10 +80,18 @@ describe('GET /api/saved_objects/resolve/{type}/{id}', () => { const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient); const logger = loggerMock.create(); loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation(); + registrationSpy = jest.spyOn(router, 'get'); + const config = setupConfig(); const access = 'public'; - registerResolveRoute(router, { config, coreUsageData, logger, access }); + registerResolveRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); @@ -142,4 +151,14 @@ describe('GET /api/saved_objects/resolve/{type}/{id}', () => { .expect(200); expect(loggerWarnSpy).toHaveBeenCalledTimes(1); }); + + it('passes deprecation configuration to the router arguments', async () => { + await supertest(httpSetup.server.listener) + .get('/api/saved_objects/resolve/index-pattern/logstash-*') + .set('x-elastic-internal-origin', 'kibana') + .expect(200); + expect(registrationSpy.mock.calls[0][0]).toMatchObject({ + options: { deprecated: deprecationMock }, + }); + }); }); diff --git a/src/core/server/integration_tests/saved_objects/routes/routes_test_utils.ts b/src/core/server/integration_tests/saved_objects/routes/routes_test_utils.ts index b27b2b72aba9..3c78b4e7f0e3 100644 --- a/src/core/server/integration_tests/saved_objects/routes/routes_test_utils.ts +++ b/src/core/server/integration_tests/saved_objects/routes/routes_test_utils.ts @@ -15,3 +15,19 @@ export function setupConfig(allowAccess: boolean = false) { } as SavedObjectConfig; return config; } + +export const deprecationMock = { + documentationUrl: 'http://elastic.co', + severity: 'warning' as const, + reason: { + type: 'deprecate' as const, + }, +}; + +export const legacyDeprecationMock = { + documentationUrl: 'http://elastic.co', + severity: 'warning' as const, + reason: { + type: 'remove' as const, + }, +}; diff --git a/src/core/server/integration_tests/saved_objects/routes/update.test.ts b/src/core/server/integration_tests/saved_objects/routes/update.test.ts index 47f3ef4b7365..909121429aef 100644 --- a/src/core/server/integration_tests/saved_objects/routes/update.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/update.test.ts @@ -20,7 +20,7 @@ import { type InternalSavedObjectsRequestHandlerContext, } from '@kbn/core-saved-objects-server-internal'; import { loggerMock } from '@kbn/logging-mocks'; -import { setupConfig } from './routes_test_utils'; +import { deprecationMock, setupConfig } from './routes_test_utils'; type SetupServerReturn = Awaited>; @@ -37,6 +37,7 @@ describe('PUT /api/saved_objects/{type}/{id?}', () => { let savedObjectsClient: ReturnType; let coreUsageStatsClient: jest.Mocked; let loggerWarnSpy: jest.SpyInstance; + let registrationSpy: jest.SpyInstance; beforeEach(async () => { const clientResponse = { @@ -66,10 +67,17 @@ describe('PUT /api/saved_objects/{type}/{id?}', () => { const coreUsageData = coreUsageDataServiceMock.createSetupContract(coreUsageStatsClient); const logger = loggerMock.create(); loggerWarnSpy = jest.spyOn(logger, 'warn').mockImplementation(); + registrationSpy = jest.spyOn(router, 'put'); const config = setupConfig(); const access = 'public'; - registerUpdateRoute(router, { config, coreUsageData, logger, access }); + registerUpdateRoute(router, { + config, + coreUsageData, + logger, + access, + deprecationInfo: deprecationMock, + }); await server.start(); }); @@ -145,4 +153,15 @@ describe('PUT /api/saved_objects/{type}/{id?}', () => { .expect(200); expect(loggerWarnSpy).toHaveBeenCalledTimes(1); }); + + it('passes deprecation configuration to the router arguments', async () => { + await supertest(httpSetup.server.listener) + .put('/api/saved_objects/index-pattern/logstash-*') + .set('x-elastic-internal-origin', 'kibana') + .send({ attributes: { title: 'Logging test' }, version: 'log' }) + .expect(200); + expect(registrationSpy.mock.calls[0][0]).toMatchObject({ + options: { deprecated: deprecationMock }, + }); + }); }); diff --git a/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/hardening_manifest.yaml b/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/hardening_manifest.yaml index 287739cc03fe..d1d76367b4ec 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/hardening_manifest.yaml +++ b/src/dev/build/tasks/os_packages/docker_generator/templates/ironbank/hardening_manifest.yaml @@ -42,39 +42,47 @@ resources: value: 0ce56bde1853fed3e53282505bac65707385275a27816c29712ab04c187aa249797c82c58759b2b36c210d4e2683eda92359d739a8045cb8385c2c34d37cc9e1 # List of project maintainers maintainers: + # AppEx Operations Members + - email: 'brad.white@elastic.co' + name: 'Brad White' + username: 'brad.white' + cht_member: false - email: 'jon@elastic.co' name: 'Jonathan Budzenski' username: 'jbudz' cht_member: false - - email: 'brad.white@elastic.co' - name: 'Brad White' - username: 'brad.white' + # AppEx Platform Security Members + - email: 'aleh.zasypkin@elastic.co' + name: 'Aleh Zasypkin' + username: 'azasypkin' + cht_member: false + - email: 'larry.gregory@elastic.co' + name: 'Larry Gregory' + username: 'legrego' + cht_member: false + # InfoSec Members + - email: 'abby.zumstein@elastic.co' + name: 'Abby Zumstein' + username: 'azumstein' + cht_member: false + - email: 'arsalan.khan@elastic.co' + name: 'Arsalan Khan' + username: 'khanarsalan' + cht_member: false + - email: 'iaroslava.zhomir@elastic.co' + name: 'Slava Zhomir' + username: 'slava-elastic' + cht_member: false + - email: 'ryan.kam@elastic.co' + name: 'Ryan Kam' + username: 'ryankam' + cht_member: false + - email: 'saumya.shree@elastic.co' + name: 'Saumya Shree' + username: 'shreesaumya' cht_member: false + # CHT Members - email: 'klepal_alexander@bah.com' name: 'Alexander Klepal' username: 'alexander.klepal' - cht_member: true - - cht_member: false - email: larry.gregory@elastic.co - name: Larry Gregory - username: legrego - - cht_member: false - email: aleh.zasypkin@elastic.co - name: Aleh Zasypkin - username: azasypkin - - cht_member: false - email: kurt.greiner@elastic.co - name: Kurt Greiner - username: kc13greiner - - cht_member: false - email: jeramy.soucy@elastic.co - name: Jeramy Soucy - username: jeramysoucy - - cht_member: false - email: sid.mantri@elastic.co - name: Sid Mantri - username: sidmantri - - cht_member: false - email: elena.shostak@elastic.co - name: Elena Shostak - username: elena.shostak + cht_member: true \ No newline at end of file diff --git a/src/dev/i18n_tools/bin/run_i18n_check.ts b/src/dev/i18n_tools/bin/run_i18n_check.ts index ff00148ab301..f25257c3ec51 100644 --- a/src/dev/i18n_tools/bin/run_i18n_check.ts +++ b/src/dev/i18n_tools/bin/run_i18n_check.ts @@ -110,7 +110,7 @@ run( }, { title: 'Checking Untracked i18n Messages outside defined namespaces', - enabled: (_) => !ignoreUntracked || !!(filterNamespaces && filterNamespaces.length), + enabled: (_) => !ignoreUntracked && !!(filterNamespaces && filterNamespaces.length), task: (context, task) => checkUntrackedNamespacesTask(context, task, { rootPaths }), }, { diff --git a/src/dev/i18n_tools/tasks/validate_translation_files/remove_outdated_translations.ts b/src/dev/i18n_tools/tasks/validate_translation_files/remove_outdated_translations.ts index a4815c17cac9..e4f9aae6b527 100644 --- a/src/dev/i18n_tools/tasks/validate_translation_files/remove_outdated_translations.ts +++ b/src/dev/i18n_tools/tasks/validate_translation_files/remove_outdated_translations.ts @@ -67,26 +67,31 @@ const removeOutdatedMessages = ( 'outdatedMessages' | 'updatedMessages', Array<[string, string | { message: string }]> > => { - const outdatedMessages: Array<[string, string | { message: string }]> = []; - let updatedMessages = translationMessages; + return translationMessages.reduce( + (acc, [translatedId, translatedMessage]) => { + const messageDescriptor = extractedMessages.find(({ id }) => id === translatedId); + // removed from codebase + if (!messageDescriptor) { + acc.outdatedMessages.push([translatedId, translatedMessage]); + return acc; + } - updatedMessages = translationMessages.filter(([translatedId, translatedMessage]) => { - const messageDescriptor = extractedMessages.find(({ id }) => id === translatedId); - if (!messageDescriptor?.hasValuesObject) { - return true; - } - try { - verifyMessageDescriptor( - typeof translatedMessage === 'string' ? translatedMessage : translatedMessage.message, - messageDescriptor - ); - return true; - } catch (err) { - outdatedMessages.push([translatedId, translatedMessage]); - // failed to verify message against latest descriptor. remove from file. - return false; - } - }); + try { + verifyMessageDescriptor( + typeof translatedMessage === 'string' ? translatedMessage : translatedMessage.message, + messageDescriptor + ); + acc.updatedMessages.push([translatedId, translatedMessage]); + } catch (err) { + // failed to verify message against latest descriptor. remove from file. + acc.outdatedMessages.push([translatedId, translatedMessage]); + } - return { updatedMessages, outdatedMessages }; + return acc; + }, + { updatedMessages: [], outdatedMessages: [] } as Record< + 'outdatedMessages' | 'updatedMessages', + Array<[string, string | { message: string }]> + > + ); }; diff --git a/src/dev/license_checker/config.ts b/src/dev/license_checker/config.ts index 8609eef92a26..91c3903a279d 100644 --- a/src/dev/license_checker/config.ts +++ b/src/dev/license_checker/config.ts @@ -87,7 +87,7 @@ export const LICENSE_OVERRIDES = { 'jsts@1.6.2': ['Eclipse Distribution License - v 1.0'], // cf. https://github.com/bjornharrtell/jsts '@mapbox/jsonlint-lines-primitives@2.0.2': ['MIT'], // license in readme https://github.com/tmcw/jsonlint '@elastic/ems-client@8.5.3': ['Elastic License 2.0'], - '@elastic/eui@97.3.0': ['Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0'], + '@elastic/eui@97.3.1': ['Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0'], 'language-subtag-registry@0.3.21': ['CC-BY-4.0'], // retired ODC‑By license https://github.com/mattcg/language-subtag-registry 'buffers@0.1.1': ['MIT'], // license in importing module https://www.npmjs.com/package/binary '@bufbuild/protobuf@1.2.1': ['Apache-2.0'], // license (Apache-2.0 AND BSD-3-Clause) diff --git a/src/plugins/console/public/services/autocomplete.ts b/src/plugins/console/public/services/autocomplete.ts index d7c4d56d5b70..32ef978c8d58 100644 --- a/src/plugins/console/public/services/autocomplete.ts +++ b/src/plugins/console/public/services/autocomplete.ts @@ -53,7 +53,10 @@ export class AutocompleteInfo { case ENTITIES.INDICES: const includeAliases = true; const collaborator = this.mapping; - return () => this.alias.getIndices(includeAliases, collaborator); + return () => [ + ...this.alias.getIndices(includeAliases, collaborator), + ...this.dataStream.getDataStreams(), + ]; case ENTITIES.FIELDS: return this.mapping.getMappings( context.indices, diff --git a/src/plugins/console/server/routes/api/console/autocomplete_entities/index.ts b/src/plugins/console/server/routes/api/console/autocomplete_entities/index.ts index bf63f2048d66..0dacd8e93cc9 100644 --- a/src/plugins/console/server/routes/api/console/autocomplete_entities/index.ts +++ b/src/plugins/console/server/routes/api/console/autocomplete_entities/index.ts @@ -43,7 +43,10 @@ const getAliases = async (settings: SettingsToRetrieve, esClient: IScopedCluster const getDataStreams = async (settings: SettingsToRetrieve, esClient: IScopedClusterClient) => { if (settings.dataStreams) { - const dataStreams = await esClient.asCurrentUser.indices.getDataStream(); + const dataStreams = await esClient.asCurrentUser.indices.getDataStream({ + name: '*', + expand_wildcards: 'all', + }); return dataStreams; } // If the user doesn't want autocomplete suggestions, then clear any that exist. diff --git a/src/plugins/controls/common/constants.ts b/src/plugins/controls/common/constants.ts index e375a7b2315b..afd6fe66f0df 100644 --- a/src/plugins/controls/common/constants.ts +++ b/src/plugins/controls/common/constants.ts @@ -7,11 +7,25 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { ControlGroupChainingSystem } from './control_group'; import { ControlLabelPosition, ControlWidth } from './types'; -export const DEFAULT_CONTROL_WIDTH: ControlWidth = 'medium'; -export const DEFAULT_CONTROL_GROW: boolean = true; -export const DEFAULT_CONTROL_LABEL_POSITION: ControlLabelPosition = 'oneLine'; +export const CONTROL_WIDTH_OPTIONS = { SMALL: 'small', MEDIUM: 'medium', LARGE: 'large' } as const; +export const CONTROL_LABEL_POSITION_OPTIONS = { ONE_LINE: 'oneLine', TWO_LINE: 'twoLine' } as const; +export const CONTROL_CHAINING_OPTIONS = { NONE: 'NONE', HIERARCHICAL: 'HIERARCHICAL' } as const; +export const DEFAULT_CONTROL_WIDTH: ControlWidth = CONTROL_WIDTH_OPTIONS.MEDIUM; +export const DEFAULT_CONTROL_LABEL_POSITION: ControlLabelPosition = + CONTROL_LABEL_POSITION_OPTIONS.ONE_LINE; +export const DEFAULT_CONTROL_GROW: boolean = false; +export const DEFAULT_CONTROL_CHAINING: ControlGroupChainingSystem = + CONTROL_CHAINING_OPTIONS.HIERARCHICAL; +export const DEFAULT_IGNORE_PARENT_SETTINGS = { + ignoreFilters: false, + ignoreQuery: false, + ignoreTimerange: false, + ignoreValidations: false, +} as const; +export const DEFAULT_AUTO_APPLY_SELECTIONS = true; export const TIME_SLIDER_CONTROL = 'timeSlider'; export const RANGE_SLIDER_CONTROL = 'rangeSliderControl'; diff --git a/src/plugins/controls/common/control_group/types.ts b/src/plugins/controls/common/control_group/types.ts index eb47d8b13eb7..ff1e4455046b 100644 --- a/src/plugins/controls/common/control_group/types.ts +++ b/src/plugins/controls/common/control_group/types.ts @@ -9,10 +9,12 @@ import { DataViewField } from '@kbn/data-views-plugin/common'; import { ControlLabelPosition, DefaultControlState, ParentIgnoreSettings } from '../types'; +import { CONTROL_CHAINING_OPTIONS } from '../constants'; export const CONTROL_GROUP_TYPE = 'control_group'; -export type ControlGroupChainingSystem = 'HIERARCHICAL' | 'NONE'; +export type ControlGroupChainingSystem = + (typeof CONTROL_CHAINING_OPTIONS)[keyof typeof CONTROL_CHAINING_OPTIONS]; export type FieldFilterPredicate = (f: DataViewField) => boolean; @@ -45,15 +47,11 @@ export interface ControlGroupRuntimeState { - panelsJSON: string; // stringified version of ControlSerializedState - ignoreParentSettingsJSON: string; - // In runtime state, we refer to this property as `labelPosition`; - // to avoid migrations, we will continue to refer to this property as `controlStyle` in the serialized state - controlStyle: ControlLabelPosition; - // In runtime state, we refer to the inverse of this property as `autoApplySelections` - // to avoid migrations, we will continue to refer to this property as `showApplySelections` in the serialized state - showApplySelections?: boolean; + extends Omit { + // In runtime state, we refer to this property as `initialChildControlState`, but in + // the serialized state we transform the state object into an array of state objects + // to make it easier for API consumers to add new controls without specifying a uuid key. + controls: Array; } /** diff --git a/src/plugins/controls/common/index.ts b/src/plugins/controls/common/index.ts index dd9c56778bb6..031d3b348272 100644 --- a/src/plugins/controls/common/index.ts +++ b/src/plugins/controls/common/index.ts @@ -17,9 +17,15 @@ export type { } from './types'; export { + DEFAULT_CONTROL_CHAINING, DEFAULT_CONTROL_GROW, DEFAULT_CONTROL_LABEL_POSITION, DEFAULT_CONTROL_WIDTH, + DEFAULT_IGNORE_PARENT_SETTINGS, + DEFAULT_AUTO_APPLY_SELECTIONS, + CONTROL_WIDTH_OPTIONS, + CONTROL_CHAINING_OPTIONS, + CONTROL_LABEL_POSITION_OPTIONS, OPTIONS_LIST_CONTROL, RANGE_SLIDER_CONTROL, TIME_SLIDER_CONTROL, diff --git a/src/plugins/controls/common/types.ts b/src/plugins/controls/common/types.ts index d3a6261aeb9d..d38ca80cb381 100644 --- a/src/plugins/controls/common/types.ts +++ b/src/plugins/controls/common/types.ts @@ -7,12 +7,16 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export type ControlWidth = 'small' | 'medium' | 'large'; -export type ControlLabelPosition = 'twoLine' | 'oneLine'; +import { SerializableRecord } from '@kbn/utility-types'; +import { CONTROL_LABEL_POSITION_OPTIONS, CONTROL_WIDTH_OPTIONS } from './constants'; + +export type ControlWidth = (typeof CONTROL_WIDTH_OPTIONS)[keyof typeof CONTROL_WIDTH_OPTIONS]; +export type ControlLabelPosition = + (typeof CONTROL_LABEL_POSITION_OPTIONS)[keyof typeof CONTROL_LABEL_POSITION_OPTIONS]; export type TimeSlice = [number, number]; -export interface ParentIgnoreSettings { +export interface ParentIgnoreSettings extends SerializableRecord { ignoreFilters?: boolean; ignoreQuery?: boolean; ignoreTimerange?: boolean; diff --git a/src/plugins/controls/public/control_group/components/control_group_editor.tsx b/src/plugins/controls/public/control_group/components/control_group_editor.tsx index 8f1ccb4d699b..cb21c23bc9ce 100644 --- a/src/plugins/controls/public/control_group/components/control_group_editor.tsx +++ b/src/plugins/controls/public/control_group/components/control_group_editor.tsx @@ -72,7 +72,7 @@ export const ControlGroupEditor = ({ onCancel, onSave, onDeleteAll, stateManager return ( <> - +

    {ControlGroupStrings.management.getFlyoutTitle()}

    @@ -80,7 +80,7 @@ export const ControlGroupEditor = ({ onCancel, onSave, onDeleteAll, stateManager { onCancel(); }} @@ -204,7 +204,7 @@ export const ControlGroupEditor = ({ onCancel, onSave, onDeleteAll, stateManager { diff --git a/src/plugins/controls/public/control_group/control_group_renderer/control_group_renderer.tsx b/src/plugins/controls/public/control_group/control_group_renderer/control_group_renderer.tsx index 6a50c60c4e59..1a05d4b25e22 100644 --- a/src/plugins/controls/public/control_group/control_group_renderer/control_group_renderer.tsx +++ b/src/plugins/controls/public/control_group/control_group_renderer/control_group_renderer.tsx @@ -19,8 +19,11 @@ import { useSearchApi, type ViewMode as ViewModeType } from '@kbn/presentation-p import type { ControlGroupApi } from '../..'; import { CONTROL_GROUP_TYPE, + DEFAULT_CONTROL_LABEL_POSITION, type ControlGroupRuntimeState, type ControlGroupSerializedState, + DEFAULT_CONTROL_CHAINING, + DEFAULT_AUTO_APPLY_SELECTIONS, } from '../../../common'; import { type ControlGroupStateBuilder, @@ -136,16 +139,19 @@ export const ControlGroupRenderer = ({ ...initialState, editorConfig, }); - const state = { - ...omit(initialState, ['initialChildControlState', 'ignoreParentSettings']), + const state: ControlGroupSerializedState = { + ...omit(initialState, ['initialChildControlState']), editorConfig, - controlStyle: initialState?.labelPosition, - panelsJSON: JSON.stringify(initialState?.initialChildControlState ?? {}), - ignoreParentSettingsJSON: JSON.stringify(initialState?.ignoreParentSettings ?? {}), + autoApplySelections: initialState?.autoApplySelections ?? DEFAULT_AUTO_APPLY_SELECTIONS, + labelPosition: initialState?.labelPosition ?? DEFAULT_CONTROL_LABEL_POSITION, + chainingSystem: initialState?.chainingSystem ?? DEFAULT_CONTROL_CHAINING, + controls: Object.entries(initialState?.initialChildControlState ?? {}).map( + ([controlId, value]) => ({ ...value, id: controlId }) + ), }; if (!cancelled) { - setSerializedState(state as ControlGroupSerializedState); + setSerializedState(state); } })(); return () => { diff --git a/src/plugins/controls/public/control_group/control_group_strings.tsx b/src/plugins/controls/public/control_group/control_group_strings.tsx index b8f6a11abf83..f5c92d987b27 100644 --- a/src/plugins/controls/public/control_group/control_group_strings.tsx +++ b/src/plugins/controls/public/control_group/control_group_strings.tsx @@ -12,7 +12,7 @@ import { i18n } from '@kbn/i18n'; export const ControlGroupStrings = { getSaveChangesTitle: () => i18n.translate('controls.controlGroup.manageControl.saveChangesTitle', { - defaultMessage: 'Save and close', + defaultMessage: 'Save', }), getCancelTitle: () => i18n.translate('controls.controlGroup.manageControl.cancelTitle', { diff --git a/src/plugins/controls/public/control_group/get_control_group_factory.tsx b/src/plugins/controls/public/control_group/get_control_group_factory.tsx index 62af1d1f868a..c8ee296d8a30 100644 --- a/src/plugins/controls/public/control_group/get_control_group_factory.tsx +++ b/src/plugins/controls/public/control_group/get_control_group_factory.tsx @@ -33,7 +33,11 @@ import type { ControlPanelsState, ParentIgnoreSettings, } from '../../common'; -import { CONTROL_GROUP_TYPE, DEFAULT_CONTROL_LABEL_POSITION } from '../../common'; +import { + CONTROL_GROUP_TYPE, + DEFAULT_CONTROL_CHAINING, + DEFAULT_CONTROL_LABEL_POSITION, +} from '../../common'; import { openDataControlEditor } from '../controls/data_controls/open_data_control_editor'; import { coreServices, dataViewsService } from '../services/kibana_services'; import { ControlGroup } from './components/control_group'; @@ -45,8 +49,6 @@ import { initSelectionsManager } from './selections_manager'; import type { ControlGroupApi } from './types'; import { deserializeControlGroup } from './utils/serialization_utils'; -const DEFAULT_CHAINING_SYSTEM = 'HIERARCHICAL'; - export const getControlGroupEmbeddableFactory = () => { const controlGroupEmbeddableFactory: ReactEmbeddableFactory< ControlGroupSerializedState, @@ -85,7 +87,7 @@ export const getControlGroupEmbeddableFactory = () => { }); const dataViews = new BehaviorSubject(undefined); const chainingSystem$ = new BehaviorSubject( - chainingSystem ?? DEFAULT_CHAINING_SYSTEM + chainingSystem ?? DEFAULT_CONTROL_CHAINING ); const ignoreParentSettings$ = new BehaviorSubject( ignoreParentSettings @@ -108,7 +110,7 @@ export const getControlGroupEmbeddableFactory = () => { chainingSystem: [ chainingSystem$, (next: ControlGroupChainingSystem) => chainingSystem$.next(next), - (a, b) => (a ?? DEFAULT_CHAINING_SYSTEM) === (b ?? DEFAULT_CHAINING_SYSTEM), + (a, b) => (a ?? DEFAULT_CONTROL_CHAINING) === (b ?? DEFAULT_CONTROL_CHAINING), ], ignoreParentSettings: [ ignoreParentSettings$, @@ -187,14 +189,14 @@ export const getControlGroupEmbeddableFactory = () => { }); }, serializeState: () => { - const { panelsJSON, references } = controlsManager.serializeControls(); + const { controls, references } = controlsManager.serializeControls(); return { rawState: { chainingSystem: chainingSystem$.getValue(), - controlStyle: labelPosition$.getValue(), - showApplySelections: !autoApplySelections$.getValue(), - ignoreParentSettingsJSON: JSON.stringify(ignoreParentSettings$.getValue()), - panelsJSON, + labelPosition: labelPosition$.getValue(), + autoApplySelections: autoApplySelections$.getValue(), + ignoreParentSettings: ignoreParentSettings$.getValue(), + controls, }, references, }; diff --git a/src/plugins/controls/public/control_group/init_controls_manager.test.ts b/src/plugins/controls/public/control_group/init_controls_manager.test.ts index 29998325664b..d88dc5452a0e 100644 --- a/src/plugins/controls/public/control_group/init_controls_manager.test.ts +++ b/src/plugins/controls/public/control_group/init_controls_manager.test.ts @@ -263,7 +263,7 @@ describe('getNewControlState', () => { test('should contain defaults when there are no existing controls', () => { const controlsManager = initControlsManager({}, new BehaviorSubject({})); expect(controlsManager.getNewControlState()).toEqual({ - grow: true, + grow: false, width: 'medium', dataViewId: undefined, }); @@ -284,7 +284,7 @@ describe('getNewControlState', () => { new BehaviorSubject(intialControlsState) ); expect(controlsManager.getNewControlState()).toEqual({ - grow: true, + grow: false, width: 'medium', dataViewId: 'myOtherDataViewId', }); diff --git a/src/plugins/controls/public/control_group/init_controls_manager.ts b/src/plugins/controls/public/control_group/init_controls_manager.ts index ee020bf1fbd5..935845327131 100644 --- a/src/plugins/controls/public/control_group/init_controls_manager.ts +++ b/src/plugins/controls/public/control_group/init_controls_manager.ts @@ -147,9 +147,8 @@ export function initControlsManager( }, serializeControls: () => { const references: Reference[] = []; - const explicitInputPanels: { - [panelId: string]: ControlPanelState & { explicitInput: object }; - } = {}; + + const controls: Array = []; controlsInOrder$.getValue().forEach(({ id }, index) => { const controlApi = getControlApi(id); @@ -166,18 +165,18 @@ export function initControlsManager( references.push(...controlReferences); } - explicitInputPanels[id] = { + controls.push({ grow, order: index, type: controlApi.type, width, - /** Re-add the `explicitInput` layer on serialize so control group saved object retains shape */ - explicitInput: { id, ...rest }, - }; + /** Re-add the `controlConfig` layer on serialize so control group saved object retains shape */ + controlConfig: { id, ...rest }, + }); }); return { - panelsJSON: JSON.stringify(explicitInputPanels), + controls, references, }; }, diff --git a/src/plugins/controls/public/control_group/open_edit_control_group_flyout.tsx b/src/plugins/controls/public/control_group/open_edit_control_group_flyout.tsx index 54e35ab271b3..459913d98de0 100644 --- a/src/plugins/controls/public/control_group/open_edit_control_group_flyout.tsx +++ b/src/plugins/controls/public/control_group/open_edit_control_group_flyout.tsx @@ -101,6 +101,9 @@ export const openEditControlGroupFlyout = ( 'aria-label': i18n.translate('controls.controlGroup.manageControl', { defaultMessage: 'Edit control settings', }), + size: 'm', + maxWidth: 500, + paddingSize: 'm', outsideClickCloses: false, onClose: () => closeOverlay(overlay), } diff --git a/src/plugins/controls/public/control_group/utils/initialization_utils.ts b/src/plugins/controls/public/control_group/utils/initialization_utils.ts index ea785d05ac73..a35572387e1e 100644 --- a/src/plugins/controls/public/control_group/utils/initialization_utils.ts +++ b/src/plugins/controls/public/control_group/utils/initialization_utils.ts @@ -7,17 +7,18 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { DEFAULT_CONTROL_LABEL_POSITION, type ControlGroupRuntimeState } from '../../../common'; +import { + type ControlGroupRuntimeState, + DEFAULT_CONTROL_CHAINING, + DEFAULT_CONTROL_LABEL_POSITION, + DEFAULT_AUTO_APPLY_SELECTIONS, + DEFAULT_IGNORE_PARENT_SETTINGS, +} from '../../../common'; export const getDefaultControlGroupRuntimeState = (): ControlGroupRuntimeState => ({ initialChildControlState: {}, labelPosition: DEFAULT_CONTROL_LABEL_POSITION, - chainingSystem: 'HIERARCHICAL', - autoApplySelections: true, - ignoreParentSettings: { - ignoreFilters: false, - ignoreQuery: false, - ignoreTimerange: false, - ignoreValidations: false, - }, + chainingSystem: DEFAULT_CONTROL_CHAINING, + autoApplySelections: DEFAULT_AUTO_APPLY_SELECTIONS, + ignoreParentSettings: DEFAULT_IGNORE_PARENT_SETTINGS, }); diff --git a/src/plugins/controls/public/control_group/utils/serialization_utils.ts b/src/plugins/controls/public/control_group/utils/serialization_utils.ts index ad7dea582750..0a046244b732 100644 --- a/src/plugins/controls/public/control_group/utils/serialization_utils.ts +++ b/src/plugins/controls/public/control_group/utils/serialization_utils.ts @@ -16,37 +16,31 @@ import { parseReferenceName } from '../../controls/data_controls/reference_name_ export const deserializeControlGroup = ( state: SerializedPanelState ): ControlGroupRuntimeState => { - const panels = JSON.parse(state.rawState.panelsJSON); - const ignoreParentSettings = JSON.parse(state.rawState.ignoreParentSettingsJSON); + const { controls } = state.rawState; + const controlsMap = Object.fromEntries(controls.map(({ id, ...rest }) => [id, rest])); /** Inject data view references into each individual control */ const references = state.references ?? []; references.forEach((reference) => { const referenceName = reference.name; const { controlId } = parseReferenceName(referenceName); - if (panels[controlId]) { - panels[controlId].dataViewId = reference.id; + if (controlsMap[controlId]) { + controlsMap[controlId].dataViewId = reference.id; } }); - /** Flatten the state of each panel by removing `explicitInput` */ - const flattenedPanels = Object.keys(panels).reduce((prev, panelId) => { - const currentPanel = panels[panelId]; - const currentPanelExplicitInput = panels[panelId].explicitInput; + /** Flatten the state of each control by removing `controlConfig` */ + const flattenedControls = Object.keys(controlsMap).reduce((prev, controlId) => { + const currentControl = controlsMap[controlId]; + const currentControlExplicitInput = controlsMap[controlId].controlConfig; return { ...prev, - [panelId]: { ...omit(currentPanel, 'explicitInput'), ...currentPanelExplicitInput }, + [controlId]: { ...omit(currentControl, 'controlConfig'), ...currentControlExplicitInput }, }; }, {}); return { - ...omit(state.rawState, ['panelsJSON', 'ignoreParentSettingsJSON']), - initialChildControlState: flattenedPanels, - ignoreParentSettings, - autoApplySelections: - typeof state.rawState.showApplySelections === 'boolean' - ? !state.rawState.showApplySelections - : true, // Rename "showApplySelections" to "autoApplySelections" - labelPosition: state.rawState.controlStyle, // Rename "controlStyle" to "labelPosition" + ...state.rawState, + initialChildControlState: flattenedControls, }; }; diff --git a/src/plugins/controls/public/controls/data_controls/data_control_constants.tsx b/src/plugins/controls/public/controls/data_controls/data_control_constants.tsx index 6b06bd8a5243..23d4c68f6c5d 100644 --- a/src/plugins/controls/public/controls/data_controls/data_control_constants.tsx +++ b/src/plugins/controls/public/controls/data_controls/data_control_constants.tsx @@ -21,14 +21,6 @@ export const DataControlEditorStrings = { defaultMessage: 'Edit control', }), dataSource: { - getFormGroupTitle: () => - i18n.translate('controls.controlGroup.manageControl.dataSource.formGroupTitle', { - defaultMessage: 'Data source', - }), - getFormGroupDescription: () => - i18n.translate('controls.controlGroup.manageControl.dataSource.formGroupDescription', { - defaultMessage: 'Select the data view and field that you want to create a control for.', - }), getSelectDataViewMessage: () => i18n.translate('controls.controlGroup.manageControl.dataSource.selectDataViewMessage', { defaultMessage: 'Please select a data view', @@ -95,14 +87,6 @@ export const DataControlEditorStrings = { }, }, displaySettings: { - getFormGroupTitle: () => - i18n.translate('controls.controlGroup.manageControl.displaySettings.formGroupTitle', { - defaultMessage: 'Display settings', - }), - getFormGroupDescription: () => - i18n.translate('controls.controlGroup.manageControl.displaySettings.formGroupDescription', { - defaultMessage: 'Change how the control appears on your dashboard.', - }), getTitleInputTitle: () => i18n.translate('controls.controlGroup.manageControl.displaySettings.titleInputTitle', { defaultMessage: 'Label', @@ -133,7 +117,7 @@ export const DataControlEditorStrings = { }, getSaveChangesTitle: () => i18n.translate('controls.controlGroup.manageControl.saveChangesTitle', { - defaultMessage: 'Save and close', + defaultMessage: 'Save', }), getCancelTitle: () => i18n.translate('controls.controlGroup.manageControl.cancelTitle', { diff --git a/src/plugins/controls/public/controls/data_controls/data_control_editor.tsx b/src/plugins/controls/public/controls/data_controls/data_control_editor.tsx index 23fd95978ff8..a84425f350dc 100644 --- a/src/plugins/controls/public/controls/data_controls/data_control_editor.tsx +++ b/src/plugins/controls/public/controls/data_controls/data_control_editor.tsx @@ -15,7 +15,6 @@ import { EuiButtonEmpty, EuiButtonGroup, EuiCallOut, - EuiDescribedFormGroup, EuiFieldText, EuiFlexGroup, EuiFlexItem, @@ -250,20 +249,8 @@ export const DataControlEditor = - {DataControlEditorStrings.manageControl.controlTypeSettings.getFormGroupTitle( - controlFactory.getDisplayName() - )} -
    - } - description={DataControlEditorStrings.manageControl.controlTypeSettings.getFormGroupDescription( - controlFactory.getDisplayName() - )} - data-test-subj="control-editor-custom-settings" - > +
    + - +
    ); }, [fieldRegistry, controlFactory, initialState, editorState, controlGroupApi]); return ( <> - +

    {!controlId // if no ID, then we are creating a new control ? DataControlEditorStrings.manageControl.getFlyoutCreateTitle() @@ -288,156 +275,144 @@ export const DataControlEditor = - {DataControlEditorStrings.manageControl.dataSource.getFormGroupTitle()}

    } - description={DataControlEditorStrings.manageControl.dataSource.getFormGroupDescription()} - > - {!editorConfig?.hideDataViewSelector && ( - - {dataViewListError ? ( - -

    {dataViewListError.message}

    -
    - ) : ( - { - setEditorState({ ...editorState, dataViewId: newDataViewId }); - setSelectedControlType(undefined); - }} - trigger={{ - label: - selectedDataView?.getName() ?? - DataControlEditorStrings.manageControl.dataSource.getSelectDataViewMessage(), - }} - selectableProps={{ isLoading: dataViewListLoading }} - /> - )} -
    - )} - - - {fieldListError ? ( + {!editorConfig?.hideDataViewSelector && ( + + {dataViewListError ? ( -

    {fieldListError.message}

    +

    {dataViewListError.message}

    ) : ( - { - const customPredicate = editorConfig?.fieldFilterPredicate?.(field) ?? true; - return Boolean(fieldRegistry?.[field.name]) && customPredicate; + { + setEditorState({ ...editorState, dataViewId: newDataViewId }); + setSelectedControlType(undefined); }} - selectedFieldName={editorState.fieldName} - dataView={selectedDataView} - onSelectField={(field) => { - setEditorState({ ...editorState, fieldName: field.name }); - - /** - * make sure that the new field is compatible with the selected control type and, if it's not, - * reset the selected control type to the **first** compatible control type - */ - const newCompatibleControlTypes = - fieldRegistry?.[field.name]?.compatibleControlTypes ?? []; - if ( - !selectedControlType || - !newCompatibleControlTypes.includes(selectedControlType!) - ) { - setSelectedControlType(newCompatibleControlTypes[0]); - } - - /** - * set the control title (i.e. the one set by the user) + default title (i.e. the field display name) - */ - const newDefaultTitle = field.displayName ?? field.name; - setDefaultPanelTitle(newDefaultTitle); - const currentTitle = editorState.title; - if (!currentTitle || currentTitle === newDefaultTitle) { - setPanelTitle(newDefaultTitle); - } - - setControlOptionsValid(true); // reset options state + trigger={{ + label: + selectedDataView?.getName() ?? + DataControlEditorStrings.manageControl.dataSource.getSelectDataViewMessage(), }} - selectableProps={{ isLoading: dataViewListLoading || dataViewLoading }} + selectableProps={{ isLoading: dataViewListLoading }} /> )}
    + )} + + + {fieldListError ? ( + +

    {fieldListError.message}

    +
    + ) : ( + { + const customPredicate = editorConfig?.fieldFilterPredicate?.(field) ?? true; + return Boolean(fieldRegistry?.[field.name]) && customPredicate; + }} + selectedFieldName={editorState.fieldName} + dataView={selectedDataView} + onSelectField={(field) => { + setEditorState({ ...editorState, fieldName: field.name }); + + /** + * make sure that the new field is compatible with the selected control type and, if it's not, + * reset the selected control type to the **first** compatible control type + */ + const newCompatibleControlTypes = + fieldRegistry?.[field.name]?.compatibleControlTypes ?? []; + if ( + !selectedControlType || + !newCompatibleControlTypes.includes(selectedControlType!) + ) { + setSelectedControlType(newCompatibleControlTypes[0]); + } + + /** + * set the control title (i.e. the one set by the user) + default title (i.e. the field display name) + */ + const newDefaultTitle = field.displayName ?? field.name; + setDefaultPanelTitle(newDefaultTitle); + const currentTitle = editorState.title; + if (!currentTitle || currentTitle === newDefaultTitle) { + setPanelTitle(newDefaultTitle); + } + + setControlOptionsValid(true); // reset options state + }} + selectableProps={{ isLoading: dataViewListLoading || dataViewLoading }} + /> + )} +
    + + {/* wrapping in `div` so that focus gets passed properly to the form row */} +
    + +
    +
    + + { + setPanelTitle(e.target.value ?? ''); + setEditorState({ + ...editorState, + title: e.target.value === '' ? undefined : e.target.value, + }); + }} + /> + + {!editorConfig?.hideWidthSettings && ( - {/* wrapping in `div` so that focus gets passed properly to the form row */}
    - + setEditorState({ ...editorState, width: newWidth as ControlWidth }) + } + /> + + setEditorState({ ...editorState, grow: !editorState.grow })} + data-test-subj="control-editor-grow-switch" />
    - - {DataControlEditorStrings.manageControl.displaySettings.getFormGroupTitle()} - } - description={DataControlEditorStrings.manageControl.displaySettings.getFormGroupDescription()} - > - - { - setPanelTitle(e.target.value ?? ''); - setEditorState({ - ...editorState, - title: e.target.value === '' ? undefined : e.target.value, - }); - }} - /> - - {!editorConfig?.hideWidthSettings && ( - -
    - - setEditorState({ ...editorState, width: newWidth as ControlWidth }) - } - /> - - setEditorState({ ...editorState, grow: !editorState.grow })} - data-test-subj="control-editor-grow-switch" - /> -
    -
    - )} -
    + )} {!editorConfig?.hideAdditionalSettings && CustomSettingsComponent} {controlId && ( <> @@ -464,7 +439,6 @@ export const DataControlEditor = { onCancel(editorState); }} @@ -476,7 +450,7 @@ export const DataControlEditor = closeOverlay(overlay), } ); diff --git a/src/plugins/controls/public/controls/data_controls/options_list_control/components/options_list_editor_options.tsx b/src/plugins/controls/public/controls/data_controls/options_list_control/components/options_list_editor_options.tsx index e9dad12be562..f07a7cc6c58b 100644 --- a/src/plugins/controls/public/controls/data_controls/options_list_control/components/options_list_editor_options.tsx +++ b/src/plugins/controls/public/controls/data_controls/options_list_control/components/options_list_editor_options.tsx @@ -131,6 +131,7 @@ export const OptionsListEditorOptions = ({ data-test-subj="optionsListControl__selectionOptionsRadioGroup" > { @@ -146,6 +147,7 @@ export const OptionsListEditorOptions = ({ data-test-subj="optionsListControl__searchOptionsRadioGroup" > { @@ -158,6 +160,7 @@ export const OptionsListEditorOptions = ({ )} { const newStep = event.target.valueAsNumber; diff --git a/src/plugins/controls/server/control_group/control_group_migrations.test.ts b/src/plugins/controls/server/control_group/control_group_migrations.test.ts index 69b19225218e..59643d3aa19c 100644 --- a/src/plugins/controls/server/control_group/control_group_migrations.test.ts +++ b/src/plugins/controls/server/control_group/control_group_migrations.test.ts @@ -18,10 +18,8 @@ import { import { OptionsListControlState } from '../../common/options_list'; import { mockDataControlState, mockOptionsListControlState } from '../mocks'; import { removeHideExcludeAndHideExists } from './control_group_migrations'; -import { - SerializableControlGroupState, - getDefaultControlGroupState, -} from './control_group_persistence'; +import { getDefaultControlGroupState } from './control_group_persistence'; +import type { SerializableControlGroupState } from './types'; describe('migrate control group', () => { const getOptionsListControl = ( diff --git a/src/plugins/controls/server/control_group/control_group_migrations.ts b/src/plugins/controls/server/control_group/control_group_migrations.ts index a3d3d06aadaf..e737441cde71 100644 --- a/src/plugins/controls/server/control_group/control_group_migrations.ts +++ b/src/plugins/controls/server/control_group/control_group_migrations.ts @@ -14,7 +14,7 @@ import { type SerializedControlState, } from '../../common'; import { OptionsListControlState } from '../../common/options_list'; -import { SerializableControlGroupState } from './control_group_persistence'; +import { SerializableControlGroupState } from './types'; export const makeControlOrdersZeroBased = (state: SerializableControlGroupState) => { if ( diff --git a/src/plugins/controls/server/control_group/control_group_persistable_state.ts b/src/plugins/controls/server/control_group/control_group_persistable_state.ts index d59ffb216193..9e880242df12 100644 --- a/src/plugins/controls/server/control_group/control_group_persistable_state.ts +++ b/src/plugins/controls/server/control_group/control_group_persistable_state.ts @@ -20,7 +20,7 @@ import { makeControlOrdersZeroBased, removeHideExcludeAndHideExists, } from './control_group_migrations'; -import type { SerializableControlGroupState } from './control_group_persistence'; +import { SerializableControlGroupState } from './types'; const getPanelStatePrefix = (state: SerializedControlState) => `${state.explicitInput.id}:`; diff --git a/src/plugins/controls/server/control_group/control_group_persistence.ts b/src/plugins/controls/server/control_group/control_group_persistence.ts index e90aa850c6d1..bcf61b3bcc1b 100644 --- a/src/plugins/controls/server/control_group/control_group_persistence.ts +++ b/src/plugins/controls/server/control_group/control_group_persistence.ts @@ -9,37 +9,22 @@ import { SerializableRecord } from '@kbn/utility-types'; +import { ControlGroupSavedObjectState, SerializableControlGroupState } from './types'; import { + DEFAULT_CONTROL_CHAINING, DEFAULT_CONTROL_LABEL_POSITION, - type ControlGroupRuntimeState, - type ControlGroupSerializedState, - type ControlPanelState, - type SerializedControlState, + DEFAULT_IGNORE_PARENT_SETTINGS, + DEFAULT_AUTO_APPLY_SELECTIONS, } from '../../common'; export const getDefaultControlGroupState = (): SerializableControlGroupState => ({ panels: {}, labelPosition: DEFAULT_CONTROL_LABEL_POSITION, - chainingSystem: 'HIERARCHICAL', - autoApplySelections: true, - ignoreParentSettings: { - ignoreFilters: false, - ignoreQuery: false, - ignoreTimerange: false, - ignoreValidations: false, - }, + chainingSystem: DEFAULT_CONTROL_CHAINING, + autoApplySelections: DEFAULT_AUTO_APPLY_SELECTIONS, + ignoreParentSettings: DEFAULT_IGNORE_PARENT_SETTINGS, }); -// using SerializableRecord to force type to be read as serializable -export type SerializableControlGroupState = SerializableRecord & - Omit< - ControlGroupRuntimeState, - 'initialChildControlState' | 'ignoreParentSettings' | 'editorConfig' // editor config is not persisted - > & { - ignoreParentSettings: Record; - panels: Record> | {}; - }; - const safeJSONParse = (jsonString?: string): OutType | undefined => { if (!jsonString && typeof jsonString !== 'string') return; try { @@ -49,22 +34,26 @@ const safeJSONParse = (jsonString?: string): OutType | undefined => { } }; -export const controlGroupSerializedStateToSerializableRuntimeState = ( - serializedState: ControlGroupSerializedState +export const controlGroupSavedObjectStateToSerializableRuntimeState = ( + savedObjectState: ControlGroupSavedObjectState ): SerializableControlGroupState => { const defaultControlGroupInput = getDefaultControlGroupState(); return { - chainingSystem: serializedState?.chainingSystem, - labelPosition: serializedState?.controlStyle ?? defaultControlGroupInput.labelPosition, - autoApplySelections: !serializedState?.showApplySelections, - ignoreParentSettings: safeJSONParse(serializedState?.ignoreParentSettingsJSON) ?? {}, - panels: safeJSONParse(serializedState?.panelsJSON) ?? {}, + chainingSystem: + (savedObjectState?.chainingSystem as SerializableControlGroupState['chainingSystem']) ?? + defaultControlGroupInput.chainingSystem, + labelPosition: + (savedObjectState?.controlStyle as SerializableControlGroupState['labelPosition']) ?? + defaultControlGroupInput.labelPosition, + autoApplySelections: !savedObjectState?.showApplySelections, + ignoreParentSettings: safeJSONParse(savedObjectState?.ignoreParentSettingsJSON) ?? {}, + panels: safeJSONParse(savedObjectState?.panelsJSON) ?? {}, }; }; -export const serializableRuntimeStateToControlGroupSerializedState = ( +export const serializableRuntimeStateToControlGroupSavedObjectState = ( serializable: SerializableRecord // It is safe to treat this as SerializableControlGroupState -): ControlGroupSerializedState => { +): ControlGroupSavedObjectState => { return { controlStyle: serializable.labelPosition as SerializableControlGroupState['labelPosition'], chainingSystem: serializable.chainingSystem as SerializableControlGroupState['chainingSystem'], diff --git a/src/plugins/controls/server/control_group/control_group_telemetry.test.ts b/src/plugins/controls/server/control_group/control_group_telemetry.test.ts index da2800a7d744..3647a23d36a1 100644 --- a/src/plugins/controls/server/control_group/control_group_telemetry.test.ts +++ b/src/plugins/controls/server/control_group/control_group_telemetry.test.ts @@ -7,16 +7,11 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { SerializableRecord } from '@kbn/utility-types'; -import { type ControlGroupSerializedState } from '../../common'; -import { - type ControlGroupTelemetry, - controlGroupTelemetry, - initializeControlGroupTelemetry, -} from './control_group_telemetry'; +import { controlGroupTelemetry, initializeControlGroupTelemetry } from './control_group_telemetry'; +import { ControlGroupSavedObjectState, ControlGroupTelemetry } from './types'; // controls attributes with all settings ignored + 3 options lists + hierarchical chaining + label above -const rawControlAttributes1: SerializableRecord & ControlGroupSerializedState = { +const rawControlAttributes1: ControlGroupSavedObjectState = { controlStyle: 'twoLine', chainingSystem: 'NONE', showApplySelections: true, @@ -27,7 +22,7 @@ const rawControlAttributes1: SerializableRecord & ControlGroupSerializedState = }; // controls attributes with some settings ignored + 2 range sliders, 1 time slider + No chaining + label inline -const rawControlAttributes2: SerializableRecord & ControlGroupSerializedState = { +const rawControlAttributes2: ControlGroupSavedObjectState = { controlStyle: 'oneLine', chainingSystem: 'NONE', showApplySelections: false, @@ -38,7 +33,7 @@ const rawControlAttributes2: SerializableRecord & ControlGroupSerializedState = }; // controls attributes with no settings ignored + 2 options lists, 1 range slider, 1 time slider + hierarchical chaining + label inline -const rawControlAttributes3: SerializableRecord & ControlGroupSerializedState = { +const rawControlAttributes3: ControlGroupSavedObjectState = { controlStyle: 'oneLine', chainingSystem: 'HIERARCHICAL', showApplySelections: false, diff --git a/src/plugins/controls/server/control_group/control_group_telemetry.ts b/src/plugins/controls/server/control_group/control_group_telemetry.ts index 21d1baf40116..72944202b955 100644 --- a/src/plugins/controls/server/control_group/control_group_telemetry.ts +++ b/src/plugins/controls/server/control_group/control_group_telemetry.ts @@ -9,31 +9,15 @@ import { PersistableStateService } from '@kbn/kibana-utils-plugin/common'; import { set } from '@kbn/safer-lodash-set'; -import type { ControlGroupSerializedState } from '../../common'; import { - type SerializableControlGroupState, - controlGroupSerializedStateToSerializableRuntimeState, + controlGroupSavedObjectStateToSerializableRuntimeState, getDefaultControlGroupState, } from './control_group_persistence'; - -export interface ControlGroupTelemetry { - total: number; - chaining_system: { - [key: string]: number; - }; - label_position: { - [key: string]: number; - }; - ignore_settings: { - [key: string]: number; - }; - by_type: { - [key: string]: { - total: number; - details: { [key: string]: number }; - }; - }; -} +import { + ControlGroupSavedObjectState, + ControlGroupTelemetry, + SerializableControlGroupState, +} from './types'; export const initializeControlGroupTelemetry = ( statsSoFar: Record @@ -113,8 +97,8 @@ export const controlGroupTelemetry: PersistableStateService['telemetry'] = ( const controlGroupStats = initializeControlGroupTelemetry(stats); const controlGroupState = { ...getDefaultControlGroupState(), - ...controlGroupSerializedStateToSerializableRuntimeState( - state as unknown as ControlGroupSerializedState + ...controlGroupSavedObjectStateToSerializableRuntimeState( + state as unknown as ControlGroupSavedObjectState ), }; if (!controlGroupState) return controlGroupStats; diff --git a/src/plugins/controls/server/control_group/types.ts b/src/plugins/controls/server/control_group/types.ts new file mode 100644 index 000000000000..9aa0aaddc4a1 --- /dev/null +++ b/src/plugins/controls/server/control_group/types.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 { SerializableRecord } from '@kbn/utility-types'; +import { ControlGroupRuntimeState, ControlPanelState, SerializedControlState } from '../../common'; + +// using SerializableRecord to force type to be read as serializable +export type SerializableControlGroupState = SerializableRecord & + Omit< + ControlGroupRuntimeState, + 'initialChildControlState' | 'editorConfig' // editor config is not persisted + > & { + panels: Record> | {}; + }; + +export type ControlGroupSavedObjectState = SerializableRecord & { + chainingSystem: SerializableControlGroupState['chainingSystem']; + controlStyle: SerializableControlGroupState['labelPosition']; + showApplySelections: boolean; + ignoreParentSettingsJSON: string; + panelsJSON: string; +}; + +export interface ControlGroupTelemetry { + total: number; + chaining_system: { + [key: string]: number; + }; + label_position: { + [key: string]: number; + }; + ignore_settings: { + [key: string]: number; + }; + by_type: { + [key: string]: { + total: number; + details: { [key: string]: number }; + }; + }; +} diff --git a/src/plugins/controls/server/index.ts b/src/plugins/controls/server/index.ts index 541d9e2a4620..40261f8a3013 100644 --- a/src/plugins/controls/server/index.ts +++ b/src/plugins/controls/server/index.ts @@ -13,10 +13,9 @@ export const plugin = async () => { }; export { - controlGroupSerializedStateToSerializableRuntimeState, - serializableRuntimeStateToControlGroupSerializedState, + controlGroupSavedObjectStateToSerializableRuntimeState, + serializableRuntimeStateToControlGroupSavedObjectState, } from './control_group/control_group_persistence'; -export { - type ControlGroupTelemetry, - initializeControlGroupTelemetry, -} from './control_group/control_group_telemetry'; +export { initializeControlGroupTelemetry } from './control_group/control_group_telemetry'; + +export type { ControlGroupTelemetry } from './control_group/types'; diff --git a/src/plugins/controls/tsconfig.json b/src/plugins/controls/tsconfig.json index e1040faecc1b..41ab33dc1896 100644 --- a/src/plugins/controls/tsconfig.json +++ b/src/plugins/controls/tsconfig.json @@ -38,7 +38,7 @@ "@kbn/field-formats-plugin", "@kbn/presentation-panel-plugin", "@kbn/shared-ux-utility", - "@kbn/std" + "@kbn/std", ], "exclude": ["target/**/*"] } diff --git a/src/plugins/dashboard/common/bwc/types.ts b/src/plugins/dashboard/common/bwc/types.ts index b1b97fa31485..ae409d143656 100644 --- a/src/plugins/dashboard/common/bwc/types.ts +++ b/src/plugins/dashboard/common/bwc/types.ts @@ -9,7 +9,7 @@ import type { SavedObjectReference } from '@kbn/core/public'; import type { Serializable } from '@kbn/utility-types'; -import { GridData } from '../content_management'; +import type { GridData } from '../../server/dashboard_saved_object'; interface KibanaAttributes { kibanaSavedObjectMeta: { diff --git a/src/plugins/dashboard/common/content_management/constants.ts b/src/plugins/dashboard/common/content_management/constants.ts index 29c679872a9e..978271680af1 100644 --- a/src/plugins/dashboard/common/content_management/constants.ts +++ b/src/plugins/dashboard/common/content_management/constants.ts @@ -7,6 +7,18 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export const LATEST_VERSION = 2; +export const LATEST_VERSION = 3; export const CONTENT_ID = 'dashboard'; + +export const DASHBOARD_GRID_COLUMN_COUNT = 48; +export const DEFAULT_PANEL_WIDTH = DASHBOARD_GRID_COLUMN_COUNT / 2; +export const DEFAULT_PANEL_HEIGHT = 15; + +export const DEFAULT_DASHBOARD_OPTIONS = { + hidePanelTitles: false, + useMargins: true, + syncColors: true, + syncCursor: true, + syncTooltips: true, +} as const; diff --git a/src/plugins/dashboard/common/content_management/index.ts b/src/plugins/dashboard/common/content_management/index.ts index d87d65a61d4f..b87b54520d7a 100644 --- a/src/plugins/dashboard/common/content_management/index.ts +++ b/src/plugins/dashboard/common/content_management/index.ts @@ -7,14 +7,13 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export { LATEST_VERSION, CONTENT_ID } from './constants'; +export { + LATEST_VERSION, + CONTENT_ID, + DASHBOARD_GRID_COLUMN_COUNT, + DEFAULT_PANEL_HEIGHT, + DEFAULT_PANEL_WIDTH, + DEFAULT_DASHBOARD_OPTIONS, +} from './constants'; export type { DashboardContentType } from './types'; - -export type { - GridData, - DashboardItem, - DashboardCrudTypes, - DashboardAttributes, - SavedDashboardPanel, -} from './latest'; diff --git a/src/plugins/dashboard/common/content_management/v1/types.ts b/src/plugins/dashboard/common/content_management/v1/types.ts index 9b7c2973d971..3b3317c0bd13 100644 --- a/src/plugins/dashboard/common/content_management/v1/types.ts +++ b/src/plugins/dashboard/common/content_management/v1/types.ts @@ -14,7 +14,7 @@ import type { } from '@kbn/content-management-utils'; import { Serializable } from '@kbn/utility-types'; import { RefreshInterval } from '@kbn/data-plugin/common'; -import { ControlGroupSerializedState } from '@kbn/controls-plugin/common'; +import { ControlGroupChainingSystem, ControlLabelPosition } from '@kbn/controls-plugin/common'; import { DashboardContentType } from '../types'; @@ -62,10 +62,13 @@ export interface SavedDashboardPanel { version?: string; } -type ControlGroupAttributesV1 = Pick< - ControlGroupSerializedState, - 'panelsJSON' | 'chainingSystem' | 'controlStyle' | 'ignoreParentSettingsJSON' ->; +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +export type ControlGroupAttributesV1 = { + chainingSystem?: ControlGroupChainingSystem; + panelsJSON: string; // stringified version of ControlSerializedState + ignoreParentSettingsJSON: string; + controlStyle?: ControlLabelPosition; +}; /* eslint-disable-next-line @typescript-eslint/consistent-type-definitions */ export type DashboardAttributes = { @@ -77,7 +80,7 @@ export type DashboardAttributes = { description: string; panelsJSON: string; timeFrom?: string; - version: number; + version?: number; timeTo?: string; title: string; kibanaSavedObjectMeta: { diff --git a/src/plugins/dashboard/common/content_management/v2/index.ts b/src/plugins/dashboard/common/content_management/v2/index.ts index b0b10669699c..bd687ff0dd60 100644 --- a/src/plugins/dashboard/common/content_management/v2/index.ts +++ b/src/plugins/dashboard/common/content_management/v2/index.ts @@ -8,4 +8,4 @@ */ export type { GridData, DashboardItem, SavedDashboardPanel } from '../v1/types'; // no changes made to types from v1 to v2 -export type { DashboardCrudTypes, DashboardAttributes } from './types'; +export type { ControlGroupAttributes, DashboardCrudTypes, DashboardAttributes } from './types'; diff --git a/src/plugins/dashboard/common/content_management/v2/types.ts b/src/plugins/dashboard/common/content_management/v2/types.ts index 3f009b749a2a..ae2c2a798d81 100644 --- a/src/plugins/dashboard/common/content_management/v2/types.ts +++ b/src/plugins/dashboard/common/content_management/v2/types.ts @@ -12,21 +12,18 @@ import type { SavedObjectCreateOptions, SavedObjectUpdateOptions, } from '@kbn/content-management-utils'; -import { ControlGroupSerializedState } from '@kbn/controls-plugin/common'; import { DashboardContentType } from '../types'; -import { DashboardAttributes as DashboardAttributesV1 } from '../v1/types'; +import { + ControlGroupAttributesV1, + DashboardAttributes as DashboardAttributesV1, +} from '../v1/types'; -type ControlGroupAttributesV2 = Pick< - ControlGroupSerializedState, - | 'panelsJSON' - | 'chainingSystem' - | 'controlStyle' - | 'ignoreParentSettingsJSON' - | 'showApplySelections' ->; +export type ControlGroupAttributes = ControlGroupAttributesV1 & { + showApplySelections?: boolean; +}; export type DashboardAttributes = Omit & { - controlGroupInput?: ControlGroupAttributesV2; + controlGroupInput?: ControlGroupAttributes; }; export type DashboardCrudTypes = ContentManagementCrudTypes< diff --git a/src/plugins/dashboard/common/dashboard_container/types.ts b/src/plugins/dashboard/common/dashboard_container/types.ts index bcb7670f18e1..dd3f7302038c 100644 --- a/src/plugins/dashboard/common/dashboard_container/types.ts +++ b/src/plugins/dashboard/common/dashboard_container/types.ts @@ -18,8 +18,7 @@ import type { Reference } from '@kbn/content-management-utils'; import { RefreshInterval } from '@kbn/data-plugin/common'; import { KibanaExecutionContext } from '@kbn/core-execution-context-common'; -import { DashboardOptions } from '../types'; -import { GridData } from '../content_management'; +import type { DashboardOptions, GridData } from '../../server/content_management'; export interface DashboardPanelMap { [key: string]: DashboardPanelState; diff --git a/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.test.ts b/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.test.ts index 689db61b0cb2..e9bd6aff0fe1 100644 --- a/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.test.ts +++ b/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.test.ts @@ -18,7 +18,8 @@ import { createInject, } from '../../dashboard_container/persistable_state/dashboard_container_references'; import { createEmbeddablePersistableStateServiceMock } from '@kbn/embeddable-plugin/common/mocks'; -import { DashboardAttributes } from '../../content_management'; +import type { DashboardAttributes, DashboardItem } from '../../../server/content_management'; +import { DashboardAttributesAndReferences } from '../../types'; const embeddablePersistableStateServiceMock = createEmbeddablePersistableStateServiceMock(); const dashboardInject = createInject(embeddablePersistableStateServiceMock); @@ -44,28 +45,37 @@ const deps: InjectExtractDeps = { }; const commonAttributes: DashboardAttributes = { - kibanaSavedObjectMeta: { searchSourceJSON: '' }, + kibanaSavedObjectMeta: { searchSource: {} }, timeRestore: false, - panelsJSON: '', version: 1, + options: { + hidePanelTitles: false, + useMargins: true, + syncColors: true, + syncCursor: true, + syncTooltips: true, + }, + panels: [], description: '', title: '', }; describe('extractReferences', () => { - test('extracts references from panelsJSON', () => { + test('extracts references from panels', () => { const doc = { id: '1', attributes: { ...commonAttributes, foo: true, - panelsJSON: JSON.stringify([ + panels: [ { panelIndex: 'panel-1', type: 'visualization', id: '1', title: 'Title 1', version: '7.9.1', + gridData: { x: 0, y: 0, w: 1, h: 1, i: 'panel-1' }, + panelConfig: {}, }, { panelIndex: 'panel-2', @@ -73,8 +83,10 @@ describe('extractReferences', () => { id: '2', title: 'Title 2', version: '7.9.1', + gridData: { x: 1, y: 1, w: 2, h: 2, i: 'panel-2' }, + panelConfig: {}, }, - ]), + ], }, references: [], }; @@ -86,9 +98,47 @@ describe('extractReferences', () => { "description": "", "foo": true, "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "", + "searchSource": Object {}, + }, + "options": Object { + "hidePanelTitles": false, + "syncColors": true, + "syncCursor": true, + "syncTooltips": true, + "useMargins": true, }, - "panelsJSON": "[{\\"version\\":\\"7.9.1\\",\\"type\\":\\"visualization\\",\\"panelIndex\\":\\"panel-1\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\",\\"panelRefName\\":\\"panel_panel-1\\"},{\\"version\\":\\"7.9.1\\",\\"type\\":\\"visualization\\",\\"panelIndex\\":\\"panel-2\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 2\\",\\"panelRefName\\":\\"panel_panel-2\\"}]", + "panels": Array [ + Object { + "gridData": Object { + "h": 1, + "i": "panel-1", + "w": 1, + "x": 0, + "y": 0, + }, + "panelConfig": Object {}, + "panelIndex": "panel-1", + "panelRefName": "panel_panel-1", + "title": "Title 1", + "type": "visualization", + "version": "7.9.1", + }, + Object { + "gridData": Object { + "h": 2, + "i": "panel-2", + "w": 2, + "x": 1, + "y": 1, + }, + "panelConfig": Object {}, + "panelIndex": "panel-2", + "panelRefName": "panel_panel-2", + "title": "Title 2", + "type": "visualization", + "version": "7.9.1", + }, + ], "timeRestore": false, "title": "", "version": 1, @@ -115,18 +165,18 @@ describe('extractReferences', () => { attributes: { ...commonAttributes, foo: true, - panelsJSON: JSON.stringify([ + panels: [ { id: '1', title: 'Title 1', version: '7.9.1', }, - ]), + ], }, references: [], - }; + } as unknown as DashboardAttributesAndReferences; expect(() => extractReferences(doc, deps)).toThrowErrorMatchingInlineSnapshot( - `"\\"type\\" attribute is missing from panel \\"undefined\\""` + `"\\"type\\" attribute is missing from panel \\"0\\""` ); }); @@ -136,25 +186,49 @@ describe('extractReferences', () => { attributes: { ...commonAttributes, foo: true, - panelsJSON: JSON.stringify([ + panels: [ { type: 'visualization', title: 'Title 1', version: '7.9.1', + gridData: { x: 0, y: 0, w: 1, h: 1, i: 'panel-1' }, + panelConfig: {}, }, - ]), + ], }, references: [], }; - expect(extractReferences(doc, deps)).toMatchInlineSnapshot(` + expect(extractReferences(doc as unknown as DashboardItem, deps)).toMatchInlineSnapshot(` Object { "attributes": Object { "description": "", "foo": true, "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "", + "searchSource": Object {}, + }, + "options": Object { + "hidePanelTitles": false, + "syncColors": true, + "syncCursor": true, + "syncTooltips": true, + "useMargins": true, }, - "panelsJSON": "[{\\"version\\":\\"7.9.1\\",\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\"}]", + "panels": Array [ + Object { + "gridData": Object { + "h": 1, + "i": "panel-1", + "w": 1, + "x": 0, + "y": 0, + }, + "panelConfig": Object {}, + "panelIndex": "0", + "title": "Title 1", + "type": "visualization", + "version": "7.9.1", + }, + ], "timeRestore": false, "title": "", "version": 1, @@ -171,18 +245,26 @@ describe('injectReferences', () => { ...commonAttributes, id: '1', title: 'test', - panelsJSON: JSON.stringify([ + panels: [ { + type: 'visualization', panelRefName: 'panel_0', + panelIndex: '0', title: 'Title 1', version: '7.9.0', + gridData: { x: 0, y: 0, w: 1, h: 1, i: '0' }, + panelConfig: {}, }, { + type: 'visualization', panelRefName: 'panel_1', + panelIndex: '1', title: 'Title 2', version: '7.9.0', + gridData: { x: 1, y: 1, w: 2, h: 2, i: '1' }, + panelConfig: {}, }, - ]), + ], }; const references = [ { @@ -203,9 +285,47 @@ describe('injectReferences', () => { "description": "", "id": "1", "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "", + "searchSource": Object {}, }, - "panelsJSON": "[{\\"version\\":\\"7.9.0\\",\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\",\\"id\\":\\"1\\"},{\\"version\\":\\"7.9.0\\",\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 2\\",\\"id\\":\\"2\\"}]", + "options": Object { + "hidePanelTitles": false, + "syncColors": true, + "syncCursor": true, + "syncTooltips": true, + "useMargins": true, + }, + "panels": Array [ + Object { + "gridData": Object { + "h": 1, + "i": "0", + "w": 1, + "x": 0, + "y": 0, + }, + "id": "1", + "panelConfig": Object {}, + "panelIndex": "0", + "title": "Title 1", + "type": "visualization", + "version": "7.9.0", + }, + Object { + "gridData": Object { + "h": 2, + "i": "1", + "w": 2, + "x": 1, + "y": 1, + }, + "id": "2", + "panelConfig": Object {}, + "panelIndex": "1", + "title": "Title 2", + "type": "visualization", + "version": "7.9.0", + }, + ], "timeRestore": false, "title": "test", "version": 1, @@ -213,7 +333,7 @@ describe('injectReferences', () => { `); }); - test('skips when panelsJSON is missing', () => { + test('skips when panels is missing', () => { const attributes = { id: '1', title: 'test', @@ -222,31 +342,8 @@ describe('injectReferences', () => { expect(newAttributes).toMatchInlineSnapshot(` Object { "id": "1", - "panelsJSON": "[]", - "title": "test", - } - `); - }); - - test('skips when panelsJSON is not an array', () => { - const attributes = { - ...commonAttributes, - id: '1', - panelsJSON: '{}', - title: 'test', - }; - const newAttributes = injectReferences({ attributes, references: [] }, deps); - expect(newAttributes).toMatchInlineSnapshot(` - Object { - "description": "", - "id": "1", - "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "", - }, - "panelsJSON": "[]", - "timeRestore": false, + "panels": Array [], "title": "test", - "version": 1, } `); }); @@ -256,15 +353,23 @@ describe('injectReferences', () => { ...commonAttributes, id: '1', title: 'test', - panelsJSON: JSON.stringify([ + panels: [ { + type: 'visualization', panelRefName: 'panel_0', + panelIndex: '0', title: 'Title 1', + gridData: { x: 0, y: 0, w: 1, h: 1, i: '0' }, + panelConfig: {}, }, { + type: 'visualization', + panelIndex: '1', title: 'Title 2', + gridData: { x: 1, y: 1, w: 2, h: 2, i: '1' }, + panelConfig: {}, }, - ]), + ], }; const references = [ { @@ -279,9 +384,46 @@ describe('injectReferences', () => { "description": "", "id": "1", "kibanaSavedObjectMeta": Object { - "searchSourceJSON": "", + "searchSource": Object {}, + }, + "options": Object { + "hidePanelTitles": false, + "syncColors": true, + "syncCursor": true, + "syncTooltips": true, + "useMargins": true, }, - "panelsJSON": "[{\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\",\\"id\\":\\"1\\"},{\\"embeddableConfig\\":{},\\"title\\":\\"Title 2\\"}]", + "panels": Array [ + Object { + "gridData": Object { + "h": 1, + "i": "0", + "w": 1, + "x": 0, + "y": 0, + }, + "id": "1", + "panelConfig": Object {}, + "panelIndex": "0", + "title": "Title 1", + "type": "visualization", + "version": undefined, + }, + Object { + "gridData": Object { + "h": 2, + "i": "1", + "w": 2, + "x": 1, + "y": 1, + }, + "panelConfig": Object {}, + "panelIndex": "1", + "title": "Title 2", + "type": "visualization", + "version": undefined, + }, + ], "timeRestore": false, "title": "test", "version": 1, @@ -294,12 +436,16 @@ describe('injectReferences', () => { ...commonAttributes, id: '1', title: 'test', - panelsJSON: JSON.stringify([ + panels: [ { + panelIndex: '0', panelRefName: 'panel_0', title: 'Title 1', + type: 'visualization', + gridData: { x: 0, y: 0, w: 1, h: 1, i: '0' }, + panelConfig: {}, }, - ]), + ], }; expect(() => injectReferences({ attributes, references: [] }, deps) diff --git a/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts b/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts index 1ede56a2b67a..9b9290accb51 100644 --- a/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts +++ b/src/plugins/dashboard/common/dashboard_saved_object/persistable_state/dashboard_saved_object_references.ts @@ -11,11 +11,11 @@ import type { Reference } from '@kbn/content-management-utils'; import { EmbeddablePersistableStateService } from '@kbn/embeddable-plugin/common/types'; import { - convertPanelMapToSavedPanels, - convertSavedPanelsToPanelMap, + convertPanelMapToPanelsArray, + convertPanelsArrayToPanelMap, } from '../../lib/dashboard_panel_converters'; import { DashboardAttributesAndReferences, ParsedDashboardAttributesWithType } from '../../types'; -import { DashboardAttributes, SavedDashboardPanel } from '../../content_management'; +import type { DashboardAttributes } from '../../../server/content_management'; import { createExtract, createInject, @@ -25,20 +25,12 @@ export interface InjectExtractDeps { embeddablePersistableStateService: EmbeddablePersistableStateService; } -function parseDashboardAttributesWithType( - attributes: DashboardAttributes -): ParsedDashboardAttributesWithType { - let parsedPanels = [] as SavedDashboardPanel[]; - if (typeof attributes.panelsJSON === 'string') { - const parsedJSON = JSON.parse(attributes.panelsJSON); - if (Array.isArray(parsedJSON)) { - parsedPanels = parsedJSON as SavedDashboardPanel[]; - } - } - +function parseDashboardAttributesWithType({ + panels, +}: DashboardAttributes): ParsedDashboardAttributesWithType { return { type: 'dashboard', - panels: convertSavedPanelsToPanelMap(parsedPanels), + panels: convertPanelsArrayToPanelMap(panels), } as ParsedDashboardAttributesWithType; } @@ -51,12 +43,12 @@ export function injectReferences( // inject references back into panels via the Embeddable persistable state service. const inject = createInject(deps.embeddablePersistableStateService); const injectedState = inject(parsedAttributes, references) as ParsedDashboardAttributesWithType; - const injectedPanels = convertPanelMapToSavedPanels(injectedState.panels); + const injectedPanels = convertPanelMapToPanelsArray(injectedState.panels); const newAttributes = { ...attributes, - panelsJSON: JSON.stringify(injectedPanels), - } as DashboardAttributes; + panels: injectedPanels, + }; return newAttributes; } @@ -81,12 +73,12 @@ export function extractReferences( references: Reference[]; state: ParsedDashboardAttributesWithType; }; - const extractedPanels = convertPanelMapToSavedPanels(extractedState.panels); + const extractedPanels = convertPanelMapToPanelsArray(extractedState.panels); const newAttributes = { ...attributes, - panelsJSON: JSON.stringify(extractedPanels), - } as DashboardAttributes; + panels: extractedPanels, + }; return { references: [...references, ...extractedReferences], diff --git a/src/plugins/dashboard/common/index.ts b/src/plugins/dashboard/common/index.ts index 8de0c49c41ee..be2cedf889e8 100644 --- a/src/plugins/dashboard/common/index.ts +++ b/src/plugins/dashboard/common/index.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export type { DashboardOptions, DashboardCapabilities, SharedDashboardState } from './types'; +export type { DashboardCapabilities, SharedDashboardState } from './types'; export type { DashboardPanelMap, @@ -16,9 +16,8 @@ export type { DashboardContainerByReferenceInput, } from './dashboard_container/types'; -export type { DashboardAttributes, SavedDashboardPanel } from './content_management'; - export { + type InjectExtractDeps, injectReferences, extractReferences, } from './dashboard_saved_object/persistable_state/dashboard_saved_object_references'; @@ -31,10 +30,8 @@ export { export { prefixReferencesFromPanel } from './dashboard_container/persistable_state/dashboard_container_references'; export { - convertPanelStateToSavedDashboardPanel, - convertSavedDashboardPanelToPanelState, - convertSavedPanelsToPanelMap, - convertPanelMapToSavedPanels, + convertPanelsArrayToPanelMap, + convertPanelMapToPanelsArray, } from './lib/dashboard_panel_converters'; export const UI_SETTINGS = { diff --git a/src/plugins/dashboard/common/lib/dashboard_panel_converters.ts b/src/plugins/dashboard/common/lib/dashboard_panel_converters.ts index a8c2d1f7c7b8..67317083b445 100644 --- a/src/plugins/dashboard/common/lib/dashboard_panel_converters.ts +++ b/src/plugins/dashboard/common/lib/dashboard_panel_converters.ts @@ -9,77 +9,63 @@ import { v4 } from 'uuid'; import { omit } from 'lodash'; -import { EmbeddableInput, SavedObjectEmbeddableInput } from '@kbn/embeddable-plugin/common'; +import type { SavedObjectEmbeddableInput } from '@kbn/embeddable-plugin/common'; import type { Reference } from '@kbn/content-management-utils'; -import { DashboardPanelMap, DashboardPanelState } from '..'; -import { SavedDashboardPanel } from '../content_management'; +import type { DashboardPanelMap } from '..'; +import type { DashboardPanel } from '../../server/content_management'; + import { getReferencesForPanelId, prefixReferencesFromPanel, } from '../dashboard_container/persistable_state/dashboard_container_references'; -export function convertSavedDashboardPanelToPanelState< - TEmbeddableInput extends EmbeddableInput | SavedObjectEmbeddableInput = SavedObjectEmbeddableInput ->(savedDashboardPanel: SavedDashboardPanel): DashboardPanelState { - return { - type: savedDashboardPanel.type, - gridData: savedDashboardPanel.gridData, - panelRefName: savedDashboardPanel.panelRefName, - explicitInput: { - id: savedDashboardPanel.panelIndex, - ...(savedDashboardPanel.id !== undefined && { savedObjectId: savedDashboardPanel.id }), - ...(savedDashboardPanel.title !== undefined && { title: savedDashboardPanel.title }), - ...savedDashboardPanel.embeddableConfig, - } as TEmbeddableInput, - - /** - * Version information used to be stored in the panel until 8.11 when it was moved - * to live inside the explicit Embeddable Input. If version information is given here, we'd like to keep it. - * It will be removed on Dashboard save - */ - version: savedDashboardPanel.version, - }; -} - -export function convertPanelStateToSavedDashboardPanel( - panelState: DashboardPanelState, - removeLegacyVersion?: boolean -): SavedDashboardPanel { - const savedObjectId = (panelState.explicitInput as SavedObjectEmbeddableInput).savedObjectId; - return { - /** - * Version information used to be stored in the panel until 8.11 when it was moved to live inside the - * explicit Embeddable Input. If removeLegacyVersion is not passed, we'd like to keep this information for - * the time being. - */ - ...(!removeLegacyVersion ? { version: panelState.version } : {}), - - type: panelState.type, - gridData: panelState.gridData, - panelIndex: panelState.explicitInput.id, - embeddableConfig: omit(panelState.explicitInput, ['id', 'savedObjectId', 'title']), - ...(panelState.explicitInput.title !== undefined && { title: panelState.explicitInput.title }), - ...(savedObjectId !== undefined && { id: savedObjectId }), - ...(panelState.panelRefName !== undefined && { panelRefName: panelState.panelRefName }), - }; -} - -export const convertSavedPanelsToPanelMap = (panels?: SavedDashboardPanel[]): DashboardPanelMap => { +export const convertPanelsArrayToPanelMap = (panels?: DashboardPanel[]): DashboardPanelMap => { const panelsMap: DashboardPanelMap = {}; panels?.forEach((panel, idx) => { - panelsMap![panel.panelIndex ?? String(idx)] = convertSavedDashboardPanelToPanelState(panel); + const panelIndex = panel.panelIndex ?? String(idx); + panelsMap![panel.panelIndex ?? String(idx)] = { + type: panel.type, + gridData: panel.gridData, + panelRefName: panel.panelRefName, + explicitInput: { + id: panelIndex, + ...(panel.id !== undefined && { savedObjectId: panel.id }), + ...(panel.title !== undefined && { title: panel.title }), + ...panel.panelConfig, + }, + version: panel.version, + }; }); return panelsMap; }; -export const convertPanelMapToSavedPanels = ( +export const convertPanelMapToPanelsArray = ( panels: DashboardPanelMap, removeLegacyVersion?: boolean ) => { - return Object.values(panels).map((panel) => - convertPanelStateToSavedDashboardPanel(panel, removeLegacyVersion) - ); + return Object.values(panels).map((panelState) => { + const savedObjectId = (panelState.explicitInput as SavedObjectEmbeddableInput).savedObjectId; + const panelIndex = panelState.explicitInput.id; + return { + /** + * Version information used to be stored in the panel until 8.11 when it was moved to live inside the + * explicit Embeddable Input. If removeLegacyVersion is not passed, we'd like to keep this information for + * the time being. + */ + ...(!removeLegacyVersion ? { version: panelState.version } : {}), + + type: panelState.type, + gridData: panelState.gridData, + panelIndex, + panelConfig: omit(panelState.explicitInput, ['id', 'savedObjectId', 'title']), + ...(panelState.explicitInput.title !== undefined && { + title: panelState.explicitInput.title, + }), + ...(savedObjectId !== undefined && { id: savedObjectId }), + ...(panelState.panelRefName !== undefined && { panelRefName: panelState.panelRefName }), + }; + }); }; /** diff --git a/src/plugins/dashboard/common/types.ts b/src/plugins/dashboard/common/types.ts index b3b4b1e983b2..c8ecc237ed34 100644 --- a/src/plugins/dashboard/common/types.ts +++ b/src/plugins/dashboard/common/types.ts @@ -8,17 +8,9 @@ */ import type { Reference } from '@kbn/content-management-utils'; -import { EmbeddableStateWithType } from '@kbn/embeddable-plugin/common'; -import { DashboardAttributes, SavedDashboardPanel } from './content_management'; -import { DashboardContainerInput, DashboardPanelMap } from './dashboard_container/types'; - -export interface DashboardOptions { - hidePanelTitles: boolean; - useMargins: boolean; - syncColors: boolean; - syncTooltips: boolean; - syncCursor: boolean; -} +import type { EmbeddableStateWithType } from '@kbn/embeddable-plugin/common'; +import type { DashboardContainerInput, DashboardPanelMap } from './dashboard_container/types'; +import type { DashboardAttributes, DashboardPanel } from '../server/content_management'; export interface DashboardCapabilities { showWriteControls: boolean; @@ -32,7 +24,7 @@ export interface DashboardCapabilities { * For BWC reasons, dashboard state is stored with panels as an array instead of a map */ export type SharedDashboardState = Partial< - Omit & { panels: SavedDashboardPanel[] } + Omit & { panels: DashboardPanel[] } >; /** diff --git a/src/plugins/dashboard/public/dashboard_app/_dashboard_app_strings.ts b/src/plugins/dashboard/public/dashboard_app/_dashboard_app_strings.ts index 8a6e24a183f3..9c6526ce3403 100644 --- a/src/plugins/dashboard/public/dashboard_app/_dashboard_app_strings.ts +++ b/src/plugins/dashboard/public/dashboard_app/_dashboard_app_strings.ts @@ -78,21 +78,6 @@ export const unsavedChangesBadgeStrings = { }), }; -export const leaveConfirmStrings = { - getLeaveTitle: () => - i18n.translate('dashboard.appLeaveConfirmModal.unsavedChangesTitle', { - defaultMessage: 'Unsaved changes', - }), - getLeaveSubtitle: () => - i18n.translate('dashboard.appLeaveConfirmModal.unsavedChangesSubtitle', { - defaultMessage: 'Leave Dashboard with unsaved work?', - }), - getLeaveCancelButtonText: () => - i18n.translate('dashboard.appLeaveConfirmModal.cancelButtonLabel', { - defaultMessage: 'Cancel', - }), -}; - export const getCreateVisualizationButtonTitle = () => i18n.translate('dashboard.solutionToolbar.addPanelButtonLabel', { defaultMessage: 'Create visualization', diff --git a/src/plugins/dashboard/public/dashboard_app/locator/load_dashboard_history_location_state.ts b/src/plugins/dashboard/public/dashboard_app/locator/load_dashboard_history_location_state.ts index 73832625cf11..99aa14fe6225 100644 --- a/src/plugins/dashboard/public/dashboard_app/locator/load_dashboard_history_location_state.ts +++ b/src/plugins/dashboard/public/dashboard_app/locator/load_dashboard_history_location_state.ts @@ -10,7 +10,7 @@ import { ScopedHistory } from '@kbn/core-application-browser'; import { ForwardedDashboardState } from './locator'; -import { convertSavedPanelsToPanelMap, DashboardContainerInput } from '../../../common'; +import { convertPanelsArrayToPanelMap, DashboardContainerInput } from '../../../common'; export const loadDashboardHistoryLocationState = ( getScopedHistory: () => ScopedHistory @@ -28,6 +28,6 @@ export const loadDashboardHistoryLocationState = ( return { ...restOfState, - ...{ panels: convertSavedPanelsToPanelMap(panels) }, + ...{ panels: convertPanelsArrayToPanelMap(panels) }, }; }; diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/dashboard_panel_selection_flyout.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/dashboard_panel_selection_flyout.tsx index dbb86046def0..e6adece8ab36 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/dashboard_panel_selection_flyout.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/add_new_panel/dashboard_panel_selection_flyout.tsx @@ -125,7 +125,7 @@ export const DashboardPanelSelectionListFlyout: React.FC< return ( <> - +

    { @@ -281,7 +282,7 @@ export const DashboardPanelSelectionListFlyout: React.FC< diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx index 2cad63c44202..cf7f9c65c661 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx @@ -43,7 +43,7 @@ export const EditorMenu = ({ createNewVisType, isDisabled }: EditorMenuProps) => function openDashboardPanelSelectionFlyout() { const flyoutPanelPaddingSize: ComponentProps< typeof DashboardPanelSelectionListFlyout - >['paddingSize'] = 'l'; + >['paddingSize'] = 'm'; const mount = toMountPoint( React.createElement(function () { diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.test.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.test.tsx index 41c4a55f6ab8..de7a1584dc9b 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.test.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.test.tsx @@ -8,7 +8,7 @@ */ import { Capabilities } from '@kbn/core/public'; -import { convertPanelMapToSavedPanels, DashboardContainerInput } from '../../../../common'; +import { convertPanelMapToPanelsArray, DashboardContainerInput } from '../../../../common'; import { DashboardLocatorParams } from '../../../dashboard_container'; import { shareService } from '../../../services/kibana_services'; @@ -143,7 +143,7 @@ describe('ShowShareModal', () => { ).locatorParams.params; const rawDashboardState = { ...unsavedDashboardState, - panels: convertPanelMapToSavedPanels(unsavedDashboardState.panels), + panels: convertPanelMapToPanelsArray(unsavedDashboardState.panels), }; unsavedStateKeys.forEach((key) => { expect(shareLocatorParams[key]).toStrictEqual( @@ -208,8 +208,8 @@ describe('ShowShareModal', () => { ).locatorParams.params; expect(shareLocatorParams.panels).toBeDefined(); - expect(shareLocatorParams.panels![0].embeddableConfig.changedKey1).toBe('changed'); - expect(shareLocatorParams.panels![1].embeddableConfig.changedKey2).toBe('definitely changed'); - expect(shareLocatorParams.panels![2].embeddableConfig.changedKey3).toBe('should still exist'); + expect(shareLocatorParams.panels![0].panelConfig.changedKey1).toBe('changed'); + expect(shareLocatorParams.panels![1].panelConfig.changedKey2).toBe('definitely changed'); + expect(shareLocatorParams.panels![2].panelConfig.changedKey3).toBe('should still exist'); }); }); diff --git a/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.tsx b/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.tsx index 5dd56465de92..2e3690e40d4e 100644 --- a/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.tsx +++ b/src/plugins/dashboard/public/dashboard_app/top_nav/share/show_share_modal.tsx @@ -19,7 +19,7 @@ import { ViewMode } from '@kbn/embeddable-plugin/public'; import { i18n } from '@kbn/i18n'; import { getStateFromKbnUrl, setStateToKbnUrl, unhashUrl } from '@kbn/kibana-utils-plugin/public'; -import { convertPanelMapToSavedPanels, DashboardPanelMap } from '../../../../common'; +import { convertPanelMapToPanelsArray, DashboardPanelMap } from '../../../../common'; import { DashboardLocatorParams } from '../../../dashboard_container'; import { getDashboardBackupService, @@ -151,7 +151,7 @@ export function ShowShareModal({ ...latestPanels, ...modifiedPanels, }; - return convertPanelMapToSavedPanels(allUnsavedPanelsMap); + return convertPanelMapToPanelsArray(allUnsavedPanelsMap); })(); if (unsavedDashboardState) { diff --git a/src/plugins/dashboard/public/dashboard_app/url/search_sessions_integration.ts b/src/plugins/dashboard/public/dashboard_app/url/search_sessions_integration.ts index e9ae3d6a1505..0fc8ce7173e6 100644 --- a/src/plugins/dashboard/public/dashboard_app/url/search_sessions_integration.ts +++ b/src/plugins/dashboard/public/dashboard_app/url/search_sessions_integration.ts @@ -22,7 +22,7 @@ import type { ViewMode } from '@kbn/embeddable-plugin/common'; import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; import { SEARCH_SESSION_ID } from '../../dashboard_constants'; import { DashboardLocatorParams } from '../../dashboard_container'; -import { convertPanelMapToSavedPanels } from '../../../common'; +import { convertPanelMapToPanelsArray } from '../../../common'; import { dataService } from '../../services/kibana_services'; import { DashboardApi } from '../../dashboard_api/types'; @@ -93,7 +93,7 @@ function getLocatorParams({ : undefined, panels: savedObjectId ? undefined - : (convertPanelMapToSavedPanels( + : (convertPanelMapToPanelsArray( dashboardApi.panels$.value ) as DashboardLocatorParams['panels']), }; diff --git a/src/plugins/dashboard/public/dashboard_app/url/url_utils.ts b/src/plugins/dashboard/public/dashboard_app/url/url_utils.ts index b748909eac9a..87faf87b026f 100644 --- a/src/plugins/dashboard/public/dashboard_app/url/url_utils.ts +++ b/src/plugins/dashboard/public/dashboard_app/url/url_utils.ts @@ -19,24 +19,29 @@ import { DashboardContainerInput, DashboardPanelMap, SharedDashboardState, - convertSavedPanelsToPanelMap, + convertPanelsArrayToPanelMap, } from '../../../common'; -import { SavedDashboardPanel } from '../../../common/content_management'; +import type { DashboardPanel } from '../../../server/content_management'; +import type { SavedDashboardPanel } from '../../../server/dashboard_saved_object'; import { DashboardApi } from '../../dashboard_api/types'; import { DASHBOARD_STATE_STORAGE_KEY, createDashboardEditUrl } from '../../dashboard_constants'; import { migrateLegacyQuery } from '../../services/dashboard_content_management_service/lib/load_dashboard_state'; import { coreServices } from '../../services/kibana_services'; import { getPanelTooOldErrorString } from '../_dashboard_app_strings'; +const panelIsLegacy = (panel: unknown): panel is SavedDashboardPanel => { + return (panel as SavedDashboardPanel).embeddableConfig !== undefined; +}; + /** * We no longer support loading panels from a version older than 7.3 in the URL. * @returns whether or not there is a panel in the URL state saved with a version before 7.3 */ -export const isPanelVersionTooOld = (panels: SavedDashboardPanel[]) => { +export const isPanelVersionTooOld = (panels: DashboardPanel[] | SavedDashboardPanel[]) => { for (const panel of panels) { if ( !panel.gridData || - !panel.embeddableConfig || + !((panel as DashboardPanel).panelConfig || (panel as SavedDashboardPanel).embeddableConfig) || (panel.version && semverSatisfies(panel.version, '<7.3')) ) return true; @@ -58,7 +63,19 @@ function getPanelsMap(appStateInUrl: SharedDashboardState): DashboardPanelMap | return undefined; } - return convertSavedPanelsToPanelMap(appStateInUrl.panels); + // convert legacy embeddableConfig keys to panelConfig + const panels = appStateInUrl.panels.map((panel) => { + if (panelIsLegacy(panel)) { + const { embeddableConfig, ...rest } = panel; + return { + ...rest, + panelConfig: embeddableConfig, + }; + } + return panel; + }); + + return convertPanelsArrayToPanelMap(panels); } /** diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx index 444bac28c9e6..e5355bdb2988 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/api/run_save_functions.tsx @@ -27,6 +27,7 @@ import { DashboardPanelMap, prefixReferencesFromPanel, } from '../../../../common'; +import type { DashboardAttributes } from '../../../../server/content_management'; import { DASHBOARD_CONTENT_ID, SAVED_OBJECT_POST_TIME } from '../../../dashboard_constants'; import { SaveDashboardReturn, @@ -95,7 +96,11 @@ export async function runQuickSave(this: DashboardContainer) { const { rawState: controlGroupSerializedState, references: extractedReferences } = await controlGroupApi.serializeState(); controlGroupReferences = extractedReferences; - stateToSave = { ...stateToSave, controlGroupInput: controlGroupSerializedState }; + stateToSave = { + ...stateToSave, + controlGroupInput: + controlGroupSerializedState as unknown as DashboardAttributes['controlGroupInput'], + }; } const saveResult = await getDashboardContentManagementService().saveDashboardState({ @@ -186,7 +191,8 @@ export async function runInteractiveSave(this: DashboardContainer, interactionMo controlGroupReferences = references; dashboardStateToSave = { ...dashboardStateToSave, - controlGroupInput: controlGroupSerializedState, + controlGroupInput: + controlGroupSerializedState as unknown as DashboardAttributes['controlGroupInput'], }; } diff --git a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx index a6765732c064..35137075befe 100644 --- a/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx +++ b/src/plugins/dashboard/public/dashboard_container/embeddable/dashboard_container.tsx @@ -25,7 +25,7 @@ import { v4 } from 'uuid'; import { METRIC_TYPE } from '@kbn/analytics'; import type { Reference } from '@kbn/content-management-utils'; -import { ControlGroupApi, ControlGroupSerializedState } from '@kbn/controls-plugin/public'; +import { ControlGroupApi } from '@kbn/controls-plugin/public'; import type { KibanaExecutionContext, OverlayRef } from '@kbn/core/public'; import { RefreshInterval } from '@kbn/data-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/public'; @@ -69,12 +69,8 @@ import { LocatorPublic } from '@kbn/share-plugin/common'; import { ExitFullScreenButtonKibanaProvider } from '@kbn/shared-ux-button-exit-full-screen'; import { DASHBOARD_CONTAINER_TYPE, DashboardApi, DashboardLocatorParams } from '../..'; -import { - DashboardAttributes, - DashboardContainerInput, - DashboardPanelMap, - DashboardPanelState, -} from '../../../common'; +import type { DashboardAttributes } from '../../../server/content_management'; +import { DashboardContainerInput, DashboardPanelMap, DashboardPanelState } from '../../../common'; import { getReferencesForControls, getReferencesForPanelId, @@ -887,15 +883,19 @@ export class DashboardContainer public getSerializedStateForControlGroup = () => { return { rawState: this.controlGroupInput - ? (this.controlGroupInput as ControlGroupSerializedState) - : ({ - controlStyle: 'oneLine', + ? this.controlGroupInput + : { + labelPosition: 'oneLine', chainingSystem: 'HIERARCHICAL', - showApplySelections: false, - panelsJSON: '{}', - ignoreParentSettingsJSON: - '{"ignoreFilters":false,"ignoreQuery":false,"ignoreTimerange":false,"ignoreValidations":false}', - } as ControlGroupSerializedState), + autoApplySelections: true, + controls: [], + ignoreParentSettings: { + ignoreFilters: false, + ignoreQuery: false, + ignoreTimerange: false, + ignoreValidations: false, + }, + }, references: getReferencesForControls(this.savedObjectReferences), }; }; diff --git a/src/plugins/dashboard/public/dashboard_container/panel_placement/place_clone_panel_strategy.ts b/src/plugins/dashboard/public/dashboard_container/panel_placement/place_clone_panel_strategy.ts index 8386df50717f..bdf5a39df34b 100644 --- a/src/plugins/dashboard/public/dashboard_container/panel_placement/place_clone_panel_strategy.ts +++ b/src/plugins/dashboard/public/dashboard_container/panel_placement/place_clone_panel_strategy.ts @@ -11,7 +11,7 @@ import { cloneDeep, forOwn } from 'lodash'; import { PanelNotFoundError } from '@kbn/embeddable-plugin/public'; import { DashboardPanelState } from '../../../common'; -import { GridData } from '../../../common/content_management'; +import type { GridData } from '../../../server/content_management'; import { PanelPlacementProps, PanelPlacementReturn } from './types'; import { DASHBOARD_GRID_COLUMN_COUNT } from '../../dashboard_constants'; @@ -109,9 +109,9 @@ export function placeClonePanel({ for (let j = position + 1; j < grid.length; j++) { originalPositionInTheGrid = grid[j].i; - const movedPanel = cloneDeep(otherPanels[originalPositionInTheGrid]); - movedPanel.gridData.y = movedPanel.gridData.y + diff; - otherPanels[originalPositionInTheGrid] = movedPanel; + const { gridData, ...movedPanel } = cloneDeep(otherPanels[originalPositionInTheGrid]); + const newGridData = { ...gridData, y: gridData.y + diff }; + otherPanels[originalPositionInTheGrid] = { ...movedPanel, gridData: newGridData }; } return { newPanelPlacement: bottomPlacement.grid, otherPanels }; } diff --git a/src/plugins/dashboard/public/dashboard_container/panel_placement/place_new_panel_strategies.ts b/src/plugins/dashboard/public/dashboard_container/panel_placement/place_new_panel_strategies.ts index 821a5e6eed1c..a6c0aaba4346 100644 --- a/src/plugins/dashboard/public/dashboard_container/panel_placement/place_new_panel_strategies.ts +++ b/src/plugins/dashboard/public/dashboard_container/panel_placement/place_new_panel_strategies.ts @@ -20,9 +20,9 @@ export const runPanelPlacementStrategy = ( case PanelPlacementStrategy.placeAtTop: const otherPanels = { ...currentPanels }; for (const [id, panel] of Object.entries(currentPanels)) { - const currentPanel = cloneDeep(panel); - currentPanel.gridData.y = currentPanel.gridData.y + height; - otherPanels[id] = currentPanel; + const { gridData, ...currentPanel } = cloneDeep(panel); + const newGridData = { ...gridData, y: gridData.y + height }; + otherPanels[id] = { ...currentPanel, gridData: newGridData }; } return { newPanelPlacement: { x: 0, y: 0, w: width, h: height }, diff --git a/src/plugins/dashboard/public/dashboard_container/panel_placement/types.ts b/src/plugins/dashboard/public/dashboard_container/panel_placement/types.ts index df34a9158c11..2dd826f9a582 100644 --- a/src/plugins/dashboard/public/dashboard_container/panel_placement/types.ts +++ b/src/plugins/dashboard/public/dashboard_container/panel_placement/types.ts @@ -10,7 +10,7 @@ import { EmbeddableInput } from '@kbn/embeddable-plugin/public'; import { MaybePromise } from '@kbn/utility-types'; import { DashboardPanelState } from '../../../common'; -import { GridData } from '../../../common/content_management'; +import type { GridData } from '../../../server/content_management'; import { PanelPlacementStrategy } from '../../dashboard_constants'; export interface PanelPlacementSettings { diff --git a/src/plugins/dashboard/public/dashboard_container/types.ts b/src/plugins/dashboard/public/dashboard_container/types.ts index f0b6ea2621ab..cf307924e00f 100644 --- a/src/plugins/dashboard/public/dashboard_container/types.ts +++ b/src/plugins/dashboard/public/dashboard_container/types.ts @@ -12,8 +12,8 @@ import type { ReduxEmbeddableState } from '@kbn/presentation-util-plugin/public' import { SerializableRecord } from '@kbn/utility-types'; import { ControlGroupRuntimeState } from '@kbn/controls-plugin/public'; -import type { DashboardContainerInput, DashboardOptions } from '../../common'; -import { SavedDashboardPanel } from '../../common/content_management'; +import type { DashboardContainerInput } from '../../common'; +import type { DashboardOptions, DashboardPanel } from '../../server/content_management'; export interface UnsavedPanelState { [key: string]: object | undefined; @@ -101,7 +101,7 @@ export type DashboardLocatorParams = Partial< /** * List of dashboard panels */ - panels?: Array; // used SerializableRecord here to force the GridData type to be read as serializable + panels?: Array; // used SerializableRecord here to force the GridData type to be read as serializable /** * Control group changes diff --git a/src/plugins/dashboard/public/dashboard_listing/dashboard_unsaved_listing.tsx b/src/plugins/dashboard/public/dashboard_listing/dashboard_unsaved_listing.tsx index 0e2358380130..04f40a199e83 100644 --- a/src/plugins/dashboard/public/dashboard_listing/dashboard_unsaved_listing.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/dashboard_unsaved_listing.tsx @@ -20,7 +20,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { ViewMode } from '@kbn/embeddable-plugin/public'; -import { DashboardAttributes } from '../../common/content_management'; +import type { DashboardAttributes } from '../../server/content_management'; import { DASHBOARD_PANELS_UNSAVED_ID, getDashboardBackupService, diff --git a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx index 31bfa88120a5..6c8c8f11d6a1 100644 --- a/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx +++ b/src/plugins/dashboard/public/dashboard_listing/hooks/use_dashboard_listing_table.tsx @@ -17,7 +17,7 @@ import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; import { ViewMode } from '@kbn/embeddable-plugin/public'; import { DashboardContainerInput } from '../../../common'; -import { DashboardItem } from '../../../common/content_management'; +import type { DashboardSearchOut } from '../../../server/content_management'; import { DASHBOARD_CONTENT_ID, SAVED_OBJECT_DELETE_TIME, @@ -42,7 +42,9 @@ type GetDetailViewLink = const SAVED_OBJECTS_LIMIT_SETTING = 'savedObjects:listingLimit'; const SAVED_OBJECTS_PER_PAGE_SETTING = 'savedObjects:perPage'; -const toTableListViewSavedObject = (hit: DashboardItem): DashboardSavedObjectUserContent => { +const toTableListViewSavedObject = ( + hit: DashboardSearchOut['hits'][number] +): DashboardSavedObjectUserContent => { const { title, description, timeRestore } = hit.attributes; return { type: 'dashboard', @@ -51,7 +53,7 @@ const toTableListViewSavedObject = (hit: DashboardItem): DashboardSavedObjectUse createdAt: hit.createdAt, createdBy: hit.createdBy, updatedBy: hit.updatedBy, - references: hit.references, + references: hit.references ?? [], managed: hit.managed, attributes: { title, diff --git a/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.tsx b/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.tsx index bf2be799dcc1..47a84b620ede 100644 --- a/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.tsx +++ b/src/plugins/dashboard/public/dashboard_top_nav/internal_dashboard_top_nav.tsx @@ -33,7 +33,6 @@ import { dashboardManagedBadge, getDashboardBreadcrumb, getDashboardTitle, - leaveConfirmStrings, unsavedChangesBadgeStrings, } from '../dashboard_app/_dashboard_app_strings'; import { useDashboardMountContext } from '../dashboard_app/hooks/dashboard_mount_context'; @@ -48,7 +47,6 @@ import { getDashboardRecentlyAccessedService } from '../services/dashboard_recen import { coreServices, dataService, - embeddableService, navigationService, serverlessService, } from '../services/kibana_services'; @@ -195,16 +193,6 @@ export function InternalDashboardTopNav({ */ useEffect(() => { onAppLeave((actions) => { - if ( - viewMode === 'edit' && - hasUnsavedChanges && - !embeddableService.getStateTransfer().isTransferInProgress - ) { - return actions.confirm( - leaveConfirmStrings.getLeaveSubtitle(), - leaveConfirmStrings.getLeaveTitle() - ); - } return actions.default(); }); return () => { diff --git a/src/plugins/dashboard/public/services/dashboard_content_management_service/dashboard_content_management_cache.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/dashboard_content_management_cache.ts index 1b54f9dda9eb..e72e3f23fdab 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management_service/dashboard_content_management_cache.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/dashboard_content_management_cache.ts @@ -8,14 +8,14 @@ */ import LRUCache from 'lru-cache'; -import { DashboardCrudTypes } from '../../../common/content_management'; +import type { DashboardGetOut } from '../../../server/content_management'; import { DASHBOARD_CACHE_SIZE, DASHBOARD_CACHE_TTL } from '../../dashboard_constants'; export class DashboardContentManagementCache { - private cache: LRUCache; + private cache: LRUCache; constructor() { - this.cache = new LRUCache({ + this.cache = new LRUCache({ max: DASHBOARD_CACHE_SIZE, maxAge: DASHBOARD_CACHE_TTL, }); @@ -27,7 +27,7 @@ export class DashboardContentManagementCache { } /** Add the fetched dashboard to the cache */ - public addDashboard({ item: dashboard, meta }: DashboardCrudTypes['GetOut']) { + public addDashboard({ item: dashboard, meta }: DashboardGetOut) { this.cache.set(dashboard.id, { meta, item: dashboard, diff --git a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/check_for_duplicate_dashboard_title.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/check_for_duplicate_dashboard_title.ts index 0d12cb446129..2865663dec3c 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/check_for_duplicate_dashboard_title.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/check_for_duplicate_dashboard_title.ts @@ -7,8 +7,8 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import type { DashboardSearchIn, DashboardSearchOut } from '../../../../server/content_management'; import { DASHBOARD_CONTENT_ID } from '../../../dashboard_constants'; -import { DashboardCrudTypes } from '../../../../common/content_management'; import { extractTitleAndCount } from '../../../dashboard_container/embeddable/api/lib/extract_title_and_count'; import { contentManagementService } from '../../kibana_services'; @@ -54,8 +54,8 @@ export async function checkForDuplicateDashboardTitle({ const [baseDashboardName] = extractTitleAndCount(title); const { hits } = await contentManagementService.client.search< - DashboardCrudTypes['SearchIn'], - DashboardCrudTypes['SearchOut'] + DashboardSearchIn, + DashboardSearchOut >({ contentTypeId: DASHBOARD_CONTENT_ID, query: { diff --git a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/delete_dashboards.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/delete_dashboards.ts index 0be9355ddb60..976a5579b198 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/delete_dashboards.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/delete_dashboards.ts @@ -7,18 +7,15 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getDashboardContentManagementCache } from '..'; -import { DashboardCrudTypes } from '../../../../common/content_management'; +import type { DeleteIn, DeleteResult } from '@kbn/content-management-plugin/common'; import { DASHBOARD_CONTENT_ID } from '../../../dashboard_constants'; +import { getDashboardContentManagementCache } from '..'; import { contentManagementService } from '../../kibana_services'; export const deleteDashboards = async (ids: string[]) => { const deletePromises = ids.map((id) => { getDashboardContentManagementCache().deleteDashboard(id); - return contentManagementService.client.delete< - DashboardCrudTypes['DeleteIn'], - DashboardCrudTypes['DeleteOut'] - >({ + return contentManagementService.client.delete({ contentTypeId: DASHBOARD_CONTENT_ID, id, }); diff --git a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/find_dashboards.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/find_dashboards.ts index 2f9a2c2e9a03..4afdefb8d13e 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/find_dashboards.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/find_dashboards.ts @@ -10,17 +10,20 @@ import type { Reference } from '@kbn/content-management-utils'; import { SavedObjectError, SavedObjectsFindOptionsReference } from '@kbn/core/public'; -import { getDashboardContentManagementCache } from '..'; -import { +import type { DashboardAttributes, - DashboardCrudTypes, - DashboardItem, -} from '../../../../common/content_management'; + DashboardGetIn, + DashboardGetOut, + DashboardSearchIn, + DashboardSearchOut, + DashboardSearchOptions, +} from '../../../../server/content_management'; +import { getDashboardContentManagementCache } from '..'; import { DASHBOARD_CONTENT_ID } from '../../../dashboard_constants'; import { contentManagementService } from '../../kibana_services'; export interface SearchDashboardsArgs { - options?: DashboardCrudTypes['SearchIn']['options']; + options?: DashboardSearchOptions; hasNoReference?: SavedObjectsFindOptionsReference[]; hasReference?: SavedObjectsFindOptionsReference[]; search: string; @@ -29,7 +32,7 @@ export interface SearchDashboardsArgs { export interface SearchDashboardsResponse { total: number; - hits: DashboardItem[]; + hits: DashboardSearchOut['hits']; } export async function searchDashboards({ @@ -42,10 +45,7 @@ export async function searchDashboards({ const { hits, pagination: { total }, - } = await contentManagementService.client.search< - DashboardCrudTypes['SearchIn'], - DashboardCrudTypes['SearchOut'] - >({ + } = await contentManagementService.client.search({ contentTypeId: DASHBOARD_CONTENT_ID, query: { text: search ? `${search}*` : undefined, @@ -84,10 +84,7 @@ export async function findDashboardById(id: string): Promise({ + const response = await contentManagementService.client.get({ contentTypeId: DASHBOARD_CONTENT_ID, id, }); @@ -119,8 +116,8 @@ export async function findDashboardsByIds(ids: string[]): Promise { const { hits } = await contentManagementService.client.search< - DashboardCrudTypes['SearchIn'], - DashboardCrudTypes['SearchOut'] + DashboardSearchIn, + DashboardSearchOut >({ contentTypeId: DASHBOARD_CONTENT_ID, query: { diff --git a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/load_dashboard_state.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/load_dashboard_state.ts index 17102e2fe7d0..2694411ed001 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/load_dashboard_state.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/load_dashboard_state.ts @@ -10,19 +10,15 @@ import { has } from 'lodash'; import { v4 as uuidv4 } from 'uuid'; -import { injectSearchSourceReferences, parseSearchSourceJSON } from '@kbn/data-plugin/public'; +import { injectSearchSourceReferences } from '@kbn/data-plugin/public'; import { ViewMode } from '@kbn/embeddable-plugin/public'; import { Filter, Query } from '@kbn/es-query'; import { SavedObjectNotFound } from '@kbn/kibana-utils-plugin/public'; import { cleanFiltersForSerialize } from '@kbn/presentation-util-plugin/public'; import { getDashboardContentManagementCache } from '..'; -import { - convertSavedPanelsToPanelMap, - injectReferences, - type DashboardOptions, -} from '../../../../common'; -import { DashboardCrudTypes } from '../../../../common/content_management'; +import { convertPanelsArrayToPanelMap, injectReferences } from '../../../../common'; +import type { DashboardGetIn, DashboardGetOut } from '../../../../server/content_management'; import { DASHBOARD_CONTENT_ID, DEFAULT_DASHBOARD_INPUT } from '../../../dashboard_constants'; import { contentManagementService, @@ -30,7 +26,11 @@ import { embeddableService, savedObjectsTaggingService, } from '../../kibana_services'; -import type { LoadDashboardFromSavedObjectProps, LoadDashboardReturn } from '../types'; +import type { + DashboardSearchSource, + LoadDashboardFromSavedObjectProps, + LoadDashboardReturn, +} from '../types'; import { convertNumberToDashboardVersion } from './dashboard_versioning'; import { migrateDashboardInput } from './migrate_dashboard_input'; @@ -72,8 +72,8 @@ export const loadDashboardState = async ({ /** * Load the saved object from Content Management */ - let rawDashboardContent: DashboardCrudTypes['GetOut']['item']; - let resolveMeta: DashboardCrudTypes['GetOut']['meta']; + let rawDashboardContent: DashboardGetOut['item']; + let resolveMeta: DashboardGetOut['meta']; const cachedDashboard = dashboardContentManagementCache.fetchDashboard(id); if (cachedDashboard) { @@ -82,7 +82,7 @@ export const loadDashboardState = async ({ } else { /** Otherwise, fetch and load the dashboard from the content management client, and add it to the cache */ const result = await contentManagementService.client - .get({ + .get({ contentTypeId: DASHBOARD_CONTENT_ID, id, }) @@ -127,14 +127,16 @@ export const loadDashboardState = async ({ /** * Create search source and pull filters and query from it. */ - const searchSourceJSON = attributes.kibanaSavedObjectMeta.searchSourceJSON; + let searchSourceValues = attributes.kibanaSavedObjectMeta.searchSource; const searchSource = await (async () => { - if (!searchSourceJSON) { + if (!searchSourceValues) { return await dataSearchService.searchSource.create(); } try { - let searchSourceValues = parseSearchSourceJSON(searchSourceJSON); - searchSourceValues = injectSearchSourceReferences(searchSourceValues as any, references); + searchSourceValues = injectSearchSourceReferences( + searchSourceValues as any, + references + ) as DashboardSearchSource; return await dataSearchService.searchSource.create(searchSourceValues); } catch (error: any) { return await dataSearchService.searchSource.create(); @@ -151,8 +153,8 @@ export const loadDashboardState = async ({ refreshInterval, description, timeRestore, - optionsJSON, - panelsJSON, + options, + panels, timeFrom, version, timeTo, @@ -167,11 +169,7 @@ export const loadDashboardState = async ({ } : undefined; - /** - * Parse panels and options from JSON - */ - const options: DashboardOptions = optionsJSON ? JSON.parse(optionsJSON) : undefined; - const panels = convertSavedPanelsToPanelMap(panelsJSON ? JSON.parse(panelsJSON) : []); + const panelMap = convertPanelsArrayToPanelMap(panels ?? []); const { dashboardInput, anyMigrationRun } = migrateDashboardInput({ ...DEFAULT_DASHBOARD_INPUT, @@ -183,7 +181,7 @@ export const loadDashboardState = async ({ description, timeRange, filters, - panels, + panels: panelMap, query, title, @@ -192,7 +190,7 @@ export const loadDashboardState = async ({ controlGroupInput: attributes.controlGroupInput, - version: convertNumberToDashboardVersion(version), + ...(version && { version: convertNumberToDashboardVersion(version) }), }); return { diff --git a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.test.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.test.ts index 8327397a6606..7e35b0ec1c16 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.test.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.test.ts @@ -95,7 +95,7 @@ describe('Save dashboard state', () => { currentState: { ...getSampleDashboardInput(), title: 'BooThree', - panels: { idOne: { type: 'boop' } }, + panels: { aVerySpecialVeryUniqueId: { type: 'boop' } }, } as unknown as DashboardContainerInput, lastSavedId: 'Boogatoonie', saveOptions: { saveAsCopy: true }, @@ -106,7 +106,11 @@ describe('Save dashboard state', () => { expect(contentManagementService.client.create).toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ - panelsJSON: expect.not.stringContaining('neverGonnaGetThisId'), + panels: expect.arrayContaining([ + expect.objectContaining({ + panelIndex: expect.not.stringContaining('aVerySpecialVeryUniqueId'), + }), + ]), }), }) ); diff --git a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.ts index 283ed5eed7f5..27e6a53da1f9 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/save_dashboard_state.ts @@ -13,9 +13,16 @@ import moment, { Moment } from 'moment'; import { extractSearchSourceReferences, RefreshInterval } from '@kbn/data-plugin/public'; import { isFilterPinned } from '@kbn/es-query'; +import type { SavedObjectReference } from '@kbn/core/server'; import { getDashboardContentManagementCache } from '..'; -import { convertPanelMapToSavedPanels, extractReferences } from '../../../../common'; -import { DashboardAttributes, DashboardCrudTypes } from '../../../../common/content_management'; +import { convertPanelMapToPanelsArray, extractReferences } from '../../../../common'; +import type { + DashboardAttributes, + DashboardCreateIn, + DashboardCreateOut, + DashboardUpdateIn, + DashboardUpdateOut, +} from '../../../../server/content_management'; import { generateNewPanelIds } from '../../../../common/lib/dashboard_panel_converters'; import { DASHBOARD_CONTENT_ID } from '../../../dashboard_constants'; import { LATEST_DASHBOARD_CONTAINER_VERSION } from '../../../dashboard_container'; @@ -28,7 +35,7 @@ import { embeddableService, savedObjectsTaggingService, } from '../../kibana_services'; -import { SaveDashboardProps, SaveDashboardReturn } from '../types'; +import { DashboardSearchSource, SaveDashboardProps, SaveDashboardReturn } from '../types'; import { convertDashboardVersionToNumber } from './dashboard_versioning'; export const convertTimeToUTCString = (time?: string | Moment): undefined | string => { @@ -88,33 +95,30 @@ export const saveDashboardState = async ({ // } - /** - * Stringify filters and query into search source JSON - */ - const { searchSourceJSON, searchSourceReferences } = await (async () => { - const searchSource = await dataSearchService.searchSource.create(); - searchSource.setField( + const { searchSource, searchSourceReferences } = await (async () => { + const searchSourceFields = await dataSearchService.searchSource.create(); + searchSourceFields.setField( 'filter', // save only unpinned filters filters.filter((filter) => !isFilterPinned(filter)) ); - searchSource.setField('query', query); - - const rawSearchSourceFields = searchSource.getSerializedFields(); - const [fields, references] = extractSearchSourceReferences(rawSearchSourceFields); - return { searchSourceReferences: references, searchSourceJSON: JSON.stringify(fields) }; + searchSourceFields.setField('query', query); + + const rawSearchSourceFields = searchSourceFields.getSerializedFields(); + const [fields, references] = extractSearchSourceReferences(rawSearchSourceFields) as [ + DashboardSearchSource, + SavedObjectReference[] + ]; + return { searchSourceReferences: references, searchSource: fields }; })(); - /** - * Stringify options and panels - */ - const optionsJSON = JSON.stringify({ + const options = { useMargins, syncColors, syncCursor, syncTooltips, hidePanelTitles, - }); - const panelsJSON = JSON.stringify(convertPanelMapToSavedPanels(panels, true)); + }; + const savedPanels = convertPanelMapToPanelsArray(panels, true); /** * Parse global time filter settings @@ -134,12 +138,12 @@ export const saveDashboardState = async ({ const rawDashboardAttributes: DashboardAttributes = { version: convertDashboardVersionToNumber(LATEST_DASHBOARD_CONTAINER_VERSION), controlGroupInput, - kibanaSavedObjectMeta: { searchSourceJSON }, + kibanaSavedObjectMeta: { searchSource }, description: description ?? '', refreshInterval, timeRestore, - optionsJSON, - panelsJSON, + options, + panels: savedPanels, timeFrom, title, timeTo, @@ -174,10 +178,7 @@ export const saveDashboardState = async ({ try { const result = idToSaveTo - ? await contentManagementService.client.update< - DashboardCrudTypes['UpdateIn'], - DashboardCrudTypes['UpdateOut'] - >({ + ? await contentManagementService.client.update({ id: idToSaveTo, contentTypeId: DASHBOARD_CONTENT_ID, data: attributes, @@ -187,10 +188,7 @@ export const saveDashboardState = async ({ mergeAttributes: false, }, }) - : await contentManagementService.client.create< - DashboardCrudTypes['CreateIn'], - DashboardCrudTypes['CreateOut'] - >({ + : await contentManagementService.client.create({ contentTypeId: DASHBOARD_CONTENT_ID, data: attributes, options: { diff --git a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/update_dashboard_meta.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/update_dashboard_meta.ts index 2fd57738f17a..90f31cfdc05c 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/update_dashboard_meta.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/lib/update_dashboard_meta.ts @@ -9,7 +9,7 @@ import { DashboardContainerInput } from '../../../../common'; import { DASHBOARD_CONTENT_ID } from '../../../dashboard_constants'; -import { DashboardCrudTypes } from '../../../../common/content_management'; +import type { DashboardUpdateIn, DashboardUpdateOut } from '../../../../server/content_management'; import { findDashboardsByIds } from './find_dashboards'; import { contentManagementService, savedObjectsTaggingService } from '../../kibana_services'; @@ -35,10 +35,7 @@ export const updateDashboardMeta = async ({ ? savedObjectsTaggingApi.ui.updateTagsReferences(dashboard.references, tags) : dashboard.references; - await contentManagementService.client.update< - DashboardCrudTypes['UpdateIn'], - DashboardCrudTypes['UpdateOut'] - >({ + await contentManagementService.client.update({ contentTypeId: DASHBOARD_CONTENT_ID, id, data: { title, description }, diff --git a/src/plugins/dashboard/public/services/dashboard_content_management_service/types.ts b/src/plugins/dashboard/public/services/dashboard_content_management_service/types.ts index 3294bb06c0d4..0f4fe1c86a56 100644 --- a/src/plugins/dashboard/public/services/dashboard_content_management_service/types.ts +++ b/src/plugins/dashboard/public/services/dashboard_content_management_service/types.ts @@ -8,11 +8,12 @@ */ import type { Reference } from '@kbn/content-management-utils'; +import type { Query, SerializedSearchSourceFields } from '@kbn/data-plugin/common'; import { ControlGroupRuntimeState } from '@kbn/controls-plugin/public'; import { SavedObjectSaveOpts } from '@kbn/saved-objects-plugin/public'; import { DashboardContainerInput } from '../../../common'; -import { DashboardAttributes, DashboardCrudTypes } from '../../../common/content_management'; +import type { DashboardAttributes, DashboardGetOut } from '../../../server/content_management'; import { DashboardDuplicateTitleCheckProps } from './lib/check_for_duplicate_dashboard_title'; import { FindDashboardsByIdResponse, @@ -38,7 +39,7 @@ export interface LoadDashboardFromSavedObjectProps { id?: string; } -type DashboardResolveMeta = DashboardCrudTypes['GetOut']['meta']; +type DashboardResolveMeta = DashboardGetOut['meta']; export type SavedDashboardInput = DashboardContainerInput & { /** @@ -54,6 +55,10 @@ export type SavedDashboardInput = DashboardContainerInput & { controlGroupState?: Partial; }; +export type DashboardSearchSource = Omit & { + query?: Query; +}; + export interface LoadDashboardReturn { dashboardFound: boolean; newDashboardCreated?: boolean; diff --git a/src/plugins/dashboard/public/services/mocks.ts b/src/plugins/dashboard/public/services/mocks.ts index 255098ecd819..c39c665ed55d 100644 --- a/src/plugins/dashboard/public/services/mocks.ts +++ b/src/plugins/dashboard/public/services/mocks.ts @@ -32,7 +32,8 @@ import { urlForwardingPluginMock } from '@kbn/url-forwarding-plugin/public/mocks import { visualizationsPluginMock } from '@kbn/visualizations-plugin/public/mocks'; import { setKibanaServices } from './kibana_services'; -import { DashboardAttributes, DashboardCapabilities } from '../../common'; +import { DashboardAttributes } from '../../server/content_management'; +import { DashboardCapabilities } from '../../common'; import { LoadDashboardReturn } from './dashboard_content_management_service/types'; import { SearchDashboardsResponse } from './dashboard_content_management_service/lib/find_dashboards'; diff --git a/src/plugins/dashboard/server/api/constants.ts b/src/plugins/dashboard/server/api/constants.ts new file mode 100644 index 000000000000..458165d79786 --- /dev/null +++ b/src/plugins/dashboard/server/api/constants.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", 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". + */ + +export const PUBLIC_API_VERSION = '2023-10-31'; +export const PUBLIC_API_CONTENT_MANAGEMENT_VERSION = 3; +export const PUBLIC_API_PATH = '/api/dashboards/dashboard'; diff --git a/packages/kbn-unified-field-list/src/services/field_stats_text_based/index.ts b/src/plugins/dashboard/server/api/index.ts similarity index 86% rename from packages/kbn-unified-field-list/src/services/field_stats_text_based/index.ts rename to src/plugins/dashboard/server/api/index.ts index 8915a30bf4f4..ccf84609b2b1 100644 --- a/packages/kbn-unified-field-list/src/services/field_stats_text_based/index.ts +++ b/src/plugins/dashboard/server/api/index.ts @@ -7,4 +7,4 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export { loadFieldStatsTextBased } from './load_field_stats_text_based'; +export { registerAPIRoutes } from './register_routes'; diff --git a/src/plugins/dashboard/server/api/register_routes.ts b/src/plugins/dashboard/server/api/register_routes.ts new file mode 100644 index 000000000000..692942e1bd1b --- /dev/null +++ b/src/plugins/dashboard/server/api/register_routes.ts @@ -0,0 +1,327 @@ +/* + * Copyright 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 { schema } from '@kbn/config-schema'; +import type { ContentManagementServerSetup } from '@kbn/content-management-plugin/server'; +import type { HttpServiceSetup } from '@kbn/core/server'; +import type { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import type { Logger } from '@kbn/logging'; + +import { CONTENT_ID } from '../../common/content_management'; +import { + PUBLIC_API_PATH, + PUBLIC_API_VERSION, + PUBLIC_API_CONTENT_MANAGEMENT_VERSION, +} from './constants'; +import { + dashboardAttributesSchema, + dashboardGetResultSchema, + dashboardCreateResultSchema, + dashboardSearchResultsSchema, + referenceSchema, +} from '../content_management/v3'; + +interface RegisterAPIRoutesArgs { + http: HttpServiceSetup; + contentManagement: ContentManagementServerSetup; + restCounter?: UsageCounter; + logger: Logger; +} + +const TECHNICAL_PREVIEW_WARNING = + '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.'; + +export function registerAPIRoutes({ + http, + contentManagement, + restCounter, + logger, +}: RegisterAPIRoutesArgs) { + const { versioned: versionedRouter } = http.createRouter(); + + // Create API route + const createRoute = versionedRouter.post({ + path: `${PUBLIC_API_PATH}/{id?}`, + access: 'public', + summary: 'Create a dashboard', + description: TECHNICAL_PREVIEW_WARNING, + options: { + tags: ['oas-tag:Dashboards'], + }, + }); + + createRoute.addVersion( + { + version: PUBLIC_API_VERSION, + validate: { + request: { + params: schema.object({ + id: schema.maybe(schema.string()), + }), + body: schema.object({ + attributes: dashboardAttributesSchema, + references: schema.maybe(schema.arrayOf(referenceSchema)), + spaces: schema.maybe(schema.arrayOf(schema.string())), + }), + }, + response: { + 200: { + body: () => dashboardCreateResultSchema, + }, + }, + }, + }, + async (ctx, req, res) => { + const { id } = req.params; + const { attributes, references, spaces: initialNamespaces } = req.body; + const client = contentManagement.contentClient + .getForRequest({ request: req, requestHandlerContext: ctx }) + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + let result; + try { + ({ result } = await client.create(attributes, { + id, + references, + initialNamespaces, + })); + } catch (e) { + if (e.isBoom && e.output.statusCode === 409) { + return res.conflict({ + body: { + message: `A dashboard with saved object ID ${id} already exists.`, + }, + }); + } + + if (e.isBoom && e.output.statusCode === 403) { + return res.forbidden(); + } + + return res.badRequest(); + } + + return res.ok({ body: result }); + } + ); + + // Update API route + + const updateRoute = versionedRouter.put({ + path: `${PUBLIC_API_PATH}/{id}`, + access: 'public', + summary: `Update an existing dashboard.`, + description: TECHNICAL_PREVIEW_WARNING, + options: { + tags: ['oas-tag:Dashboards'], + }, + }); + + updateRoute.addVersion( + { + version: PUBLIC_API_VERSION, + validate: { + request: { + params: schema.object({ + id: schema.string(), + }), + body: schema.object({ + attributes: dashboardAttributesSchema, + references: schema.maybe(schema.arrayOf(referenceSchema)), + }), + }, + response: { + 200: { + body: () => dashboardCreateResultSchema, + }, + }, + }, + }, + async (ctx, req, res) => { + const { attributes, references } = req.body; + const client = contentManagement.contentClient + .getForRequest({ request: req, requestHandlerContext: ctx }) + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + let result; + try { + ({ result } = await client.update(req.params.id, attributes, { references })); + } catch (e) { + if (e.isBoom && e.output.statusCode === 404) { + return res.notFound({ + body: { + message: `A dashboard with saved object ID ${req.params.id} was not found.`, + }, + }); + } + if (e.isBoom && e.output.statusCode === 403) { + return res.forbidden(); + } + return res.badRequest(e.message); + } + + return res.created({ body: result }); + } + ); + + // List API route + const listRoute = versionedRouter.get({ + path: `${PUBLIC_API_PATH}`, + access: 'public', + summary: `Get a list of dashboards.`, + description: TECHNICAL_PREVIEW_WARNING, + options: { + tags: ['oas-tag:Dashboards'], + }, + }); + + listRoute.addVersion( + { + version: PUBLIC_API_VERSION, + validate: { + request: { + query: schema.object({ + page: schema.number({ defaultValue: 1 }), + perPage: schema.maybe(schema.number()), + }), + }, + response: { + 200: { + body: () => + schema.object({ + items: schema.arrayOf(dashboardSearchResultsSchema), + total: schema.number(), + }), + }, + }, + }, + }, + async (ctx, req, res) => { + const { page, perPage: limit } = req.query; + const client = contentManagement.contentClient + .getForRequest({ request: req, requestHandlerContext: ctx }) + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + let result; + try { + // TODO add filtering + ({ result } = await client.search({ cursor: page.toString(), limit })); + } catch (e) { + if (e.isBoom && e.output.statusCode === 403) { + return res.forbidden(); + } + + return res.badRequest(); + } + + const body = { + items: result.hits, + total: result.pagination.total, + }; + return res.ok({ body }); + } + ); + + // Get API route + const getRoute = versionedRouter.get({ + path: `${PUBLIC_API_PATH}/{id}`, + access: 'public', + summary: `Get a dashboard.`, + description: TECHNICAL_PREVIEW_WARNING, + options: { + tags: ['oas-tag:Dashboards'], + }, + }); + + getRoute.addVersion( + { + version: PUBLIC_API_VERSION, + validate: { + request: { + params: schema.object({ + id: schema.string(), + }), + }, + response: { + 200: { + body: () => dashboardGetResultSchema, + }, + }, + }, + }, + async (ctx, req, res) => { + const client = contentManagement.contentClient + .getForRequest({ request: req, requestHandlerContext: ctx }) + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + let result; + try { + ({ result } = await client.get(req.params.id)); + } catch (e) { + if (e.isBoom && e.output.statusCode === 404) { + return res.notFound({ + body: { + message: `A dashboard with saved object ID ${req.params.id}] was not found.`, + }, + }); + } + + if (e.isBoom && e.output.statusCode === 403) { + return res.forbidden(); + } + + return res.badRequest(e.message); + } + + return res.ok({ body: result }); + } + ); + + // Delete API route + const deleteRoute = versionedRouter.delete({ + path: `${PUBLIC_API_PATH}/{id}`, + access: 'public', + summary: `Delete a dashboard.`, + description: TECHNICAL_PREVIEW_WARNING, + options: { + tags: ['oas-tag:Dashboards'], + }, + }); + + deleteRoute.addVersion( + { + version: PUBLIC_API_VERSION, + validate: { + request: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + }, + async (ctx, req, res) => { + const client = contentManagement.contentClient + .getForRequest({ request: req, requestHandlerContext: ctx }) + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + try { + await client.delete(req.params.id); + } catch (e) { + if (e.isBoom && e.output.statusCode === 404) { + return res.notFound({ + body: { + message: `A dashboard with saved object ID ${req.params.id} was not found.`, + }, + }); + } + if (e.isBoom && e.output.statusCode === 403) { + return res.forbidden(); + } + return res.badRequest(); + } + + return res.ok(); + } + ); +} diff --git a/src/plugins/dashboard/server/content_management/schema/cm_services.ts b/src/plugins/dashboard/server/content_management/cm_services.ts similarity index 94% rename from src/plugins/dashboard/server/content_management/schema/cm_services.ts rename to src/plugins/dashboard/server/content_management/cm_services.ts index 10fbbd7f44ba..081d7ad8a39d 100644 --- a/src/plugins/dashboard/server/content_management/schema/cm_services.ts +++ b/src/plugins/dashboard/server/content_management/cm_services.ts @@ -17,8 +17,10 @@ import type { import { serviceDefinition as v1 } from './v1'; import { serviceDefinition as v2 } from './v2'; +import { serviceDefinition as v3 } from './v3'; export const cmServicesDefinition: { [version: Version]: ServicesDefinition } = { 1: v1, 2: v2, + 3: v3, }; diff --git a/src/plugins/dashboard/server/content_management/dashboard_storage.ts b/src/plugins/dashboard/server/content_management/dashboard_storage.ts index 248979032132..e65002802989 100644 --- a/src/plugins/dashboard/server/content_management/dashboard_storage.ts +++ b/src/plugins/dashboard/server/content_management/dashboard_storage.ts @@ -7,23 +7,40 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { SOContentStorage, tagsToFindOptions } from '@kbn/content-management-utils'; -import { SavedObjectsFindOptions } from '@kbn/core-saved-objects-api-server'; +import Boom from '@hapi/boom'; +import { tagsToFindOptions } from '@kbn/content-management-utils'; +import { + SavedObjectsFindOptions, + SavedObjectsFindResult, +} from '@kbn/core-saved-objects-api-server'; import type { Logger } from '@kbn/logging'; -import { CONTENT_ID } from '../../common/content_management'; -import { cmServicesDefinition } from './schema/cm_services'; -import type { DashboardCrudTypes } from '../../common/content_management'; +import { CreateResult, DeleteResult, SearchQuery } from '@kbn/content-management-plugin/common'; +import { StorageContext } from '@kbn/content-management-plugin/server'; +import { DASHBOARD_SAVED_OBJECT_TYPE } from '../dashboard_saved_object'; +import { cmServicesDefinition } from './cm_services'; +import { DashboardSavedObjectAttributes } from '../dashboard_saved_object'; +import { itemAttrsToSavedObjectAttrs, savedObjectToItem } from './latest'; +import type { + DashboardAttributes, + DashboardItem, + DashboardCreateOut, + DashboardCreateOptions, + DashboardGetOut, + DashboardSearchOut, + DashboardUpdateOptions, + DashboardUpdateOut, + DashboardSearchOptions, +} from './latest'; const searchArgsToSOFindOptions = ( - args: DashboardCrudTypes['SearchIn'] + query: SearchQuery, + options: DashboardSearchOptions ): SavedObjectsFindOptions => { - const { query, contentTypeId, options } = args; - return { - type: contentTypeId, + type: DASHBOARD_SAVED_OBJECT_TYPE, searchFields: options?.onlyTitle ? ['title'] : ['title^3', 'description'], - fields: ['description', 'title', 'timeRestore'], + fields: options?.fields ?? ['title', 'description', 'timeRestore'], search: query.text, perPage: query.limit, page: query.cursor ? +query.cursor : undefined, @@ -32,7 +49,16 @@ const searchArgsToSOFindOptions = ( }; }; -export class DashboardStorage extends SOContentStorage { +const savedObjectClientFromRequest = async (ctx: StorageContext) => { + if (!ctx.requestHandlerContext) { + throw new Error('Storage context.requestHandlerContext missing.'); + } + + const { savedObjects } = await ctx.requestHandlerContext.core; + return savedObjects.client; +}; + +export class DashboardStorage { constructor({ logger, throwOnResultValidationError, @@ -40,26 +66,316 @@ export class DashboardStorage extends SOContentStorage { logger: Logger; throwOnResultValidationError: boolean; }) { - super({ - savedObjectType: CONTENT_ID, - cmServicesDefinition, - searchArgsToSOFindOptions, - enableMSearch: true, - allowedSavedObjectAttributes: [ - 'kibanaSavedObjectMeta', - 'controlGroupInput', - 'refreshInterval', - 'description', - 'timeRestore', - 'optionsJSON', - 'panelsJSON', - 'timeFrom', - 'version', - 'timeTo', - 'title', - ], - logger, - throwOnResultValidationError, - }); + this.logger = logger; + this.throwOnResultValidationError = throwOnResultValidationError ?? false; + this.mSearch = { + savedObjectType: DASHBOARD_SAVED_OBJECT_TYPE, + additionalSearchFields: [], + toItemResult: (ctx: StorageContext, savedObject: SavedObjectsFindResult): DashboardItem => { + const transforms = ctx.utils.getTransforms(cmServicesDefinition); + + const { item, error: itemError } = savedObjectToItem( + savedObject as SavedObjectsFindResult, + false + ); + if (itemError) { + throw Boom.badRequest(`Invalid response. ${itemError.message}`); + } + + const validationError = transforms.mSearch.out.result.validate(item); + if (validationError) { + if (this.throwOnResultValidationError) { + throw Boom.badRequest(`Invalid response. ${validationError.message}`); + } else { + this.logger.warn(`Invalid response. ${validationError.message}`); + } + } + + // Validate DB response and DOWN transform to the request version + const { value, error: resultError } = transforms.mSearch.out.result.down< + DashboardItem, + DashboardItem + >( + item, + undefined, // do not override version + { validate: false } // validation is done above + ); + + if (resultError) { + throw Boom.badRequest(`Invalid response. ${resultError.message}`); + } + + return value; + }, + }; + } + + private logger: Logger; + private throwOnResultValidationError: boolean; + + mSearch: { + savedObjectType: string; + toItemResult: (ctx: StorageContext, savedObject: SavedObjectsFindResult) => DashboardItem; + additionalSearchFields?: string[]; + }; + + async get(ctx: StorageContext, id: string): Promise { + const transforms = ctx.utils.getTransforms(cmServicesDefinition); + const soClient = await savedObjectClientFromRequest(ctx); + + // Save data in DB + const { + saved_object: savedObject, + alias_purpose: aliasPurpose, + alias_target_id: aliasTargetId, + outcome, + } = await soClient.resolve(DASHBOARD_SAVED_OBJECT_TYPE, id); + + const { item, error: itemError } = savedObjectToItem(savedObject, false); + if (itemError) { + throw Boom.badRequest(`Invalid response. ${itemError.message}`); + } + + const response = { item, meta: { aliasPurpose, aliasTargetId, outcome } }; + + const validationError = transforms.get.out.result.validate(response); + if (validationError) { + if (this.throwOnResultValidationError) { + throw Boom.badRequest(`Invalid response. ${validationError.message}`); + } else { + this.logger.warn(`Invalid response. ${validationError.message}`); + } + } + + // Validate response and DOWN transform to the request version + const { value, error: resultError } = transforms.get.out.result.down< + DashboardGetOut, + DashboardGetOut + >( + response, + undefined, // do not override version + { validate: false } // validation is done above + ); + + if (resultError) { + throw Boom.badRequest(`Invalid response. ${resultError.message}`); + } + + return value; + } + + async bulkGet(): Promise { + // Not implemented + throw new Error(`[bulkGet] has not been implemented. See DashboardStorage class.`); + } + + async create( + ctx: StorageContext, + data: DashboardAttributes, + options: DashboardCreateOptions + ): Promise { + const transforms = ctx.utils.getTransforms(cmServicesDefinition); + const soClient = await savedObjectClientFromRequest(ctx); + + // Validate input (data & options) & UP transform them to the latest version + const { value: dataToLatest, error: dataError } = transforms.create.in.data.up< + DashboardAttributes, + DashboardAttributes + >(data); + if (dataError) { + throw Boom.badRequest(`Invalid data. ${dataError.message}`); + } + + const { value: optionsToLatest, error: optionsError } = transforms.create.in.options.up< + DashboardCreateOptions, + DashboardCreateOptions + >(options); + if (optionsError) { + throw Boom.badRequest(`Invalid options. ${optionsError.message}`); + } + + const { attributes: soAttributes, error: attributesError } = + itemAttrsToSavedObjectAttrs(dataToLatest); + if (attributesError) { + throw Boom.badRequest(`Invalid data. ${attributesError.message}`); + } + + // Save data in DB + const savedObject = await soClient.create( + DASHBOARD_SAVED_OBJECT_TYPE, + soAttributes, + optionsToLatest + ); + + const { item, error: itemError } = savedObjectToItem(savedObject, false); + if (itemError) { + throw Boom.badRequest(`Invalid response. ${itemError.message}`); + } + + const validationError = transforms.create.out.result.validate({ item }); + if (validationError) { + if (this.throwOnResultValidationError) { + throw Boom.badRequest(`Invalid response. ${validationError.message}`); + } else { + this.logger.warn(`Invalid response. ${validationError.message}`); + } + } + + // Validate DB response and DOWN transform to the request version + const { value, error: resultError } = transforms.create.out.result.down< + CreateResult + >( + { item }, + undefined, // do not override version + { validate: false } // validation is done above + ); + + if (resultError) { + throw Boom.badRequest(`Invalid response. ${resultError.message}`); + } + + return value; + } + + async update( + ctx: StorageContext, + id: string, + data: DashboardAttributes, + options: DashboardUpdateOptions + ): Promise { + const transforms = ctx.utils.getTransforms(cmServicesDefinition); + const soClient = await savedObjectClientFromRequest(ctx); + + // Validate input (data & options) & UP transform them to the latest version + const { value: dataToLatest, error: dataError } = transforms.update.in.data.up< + DashboardAttributes, + DashboardAttributes + >(data); + if (dataError) { + throw Boom.badRequest(`Invalid data. ${dataError.message}`); + } + + const { value: optionsToLatest, error: optionsError } = transforms.update.in.options.up< + DashboardUpdateOptions, + DashboardUpdateOptions + >(options); + if (optionsError) { + throw Boom.badRequest(`Invalid options. ${optionsError.message}`); + } + + const { attributes: soAttributes, error: attributesError } = + itemAttrsToSavedObjectAttrs(dataToLatest); + if (attributesError) { + throw Boom.badRequest(`Invalid data. ${attributesError.message}`); + } + + // Save data in DB + const partialSavedObject = await soClient.update( + DASHBOARD_SAVED_OBJECT_TYPE, + id, + soAttributes, + optionsToLatest + ); + + const { item, error: itemError } = savedObjectToItem(partialSavedObject, true); + if (itemError) { + throw Boom.badRequest(`Invalid response. ${itemError.message}`); + } + + const validationError = transforms.update.out.result.validate({ item }); + if (validationError) { + if (this.throwOnResultValidationError) { + throw Boom.badRequest(`Invalid response. ${validationError.message}`); + } else { + this.logger.warn(`Invalid response. ${validationError.message}`); + } + } + + // Validate DB response and DOWN transform to the request version + const { value, error: resultError } = transforms.update.out.result.down< + DashboardUpdateOut, + DashboardUpdateOut + >( + { item }, + undefined, // do not override version + { validate: false } // validation is done above + ); + + if (resultError) { + throw Boom.badRequest(`Invalid response. ${resultError.message}`); + } + + return value; + } + + async delete( + ctx: StorageContext, + id: string, + // force is necessary to delete saved objects that exist in multiple namespaces + options?: { force: boolean } + ): Promise { + const soClient = await savedObjectClientFromRequest(ctx); + await soClient.delete(DASHBOARD_SAVED_OBJECT_TYPE, id, { force: options?.force ?? false }); + return { success: true }; + } + + async search( + ctx: StorageContext, + query: SearchQuery, + options: DashboardSearchOptions + ): Promise { + const transforms = ctx.utils.getTransforms(cmServicesDefinition); + const soClient = await savedObjectClientFromRequest(ctx); + + // Validate and UP transform the options + const { value: optionsToLatest, error: optionsError } = transforms.search.in.options.up< + DashboardSearchOptions, + DashboardSearchOptions + >(options); + if (optionsError) { + throw Boom.badRequest(`Invalid payload. ${optionsError.message}`); + } + + const soQuery = searchArgsToSOFindOptions(query, optionsToLatest); + // Execute the query in the DB + const soResponse = await soClient.find(soQuery); + const hits = soResponse.saved_objects + .map((so) => { + const { item } = savedObjectToItem(so, false, soQuery.fields); + return item; + }) + // Ignore any saved objects that failed to convert to items. + .filter((item) => item !== null); + const response = { + hits, + pagination: { + total: soResponse.total, + }, + }; + + const validationError = transforms.search.out.result.validate(response); + if (validationError) { + if (this.throwOnResultValidationError) { + throw Boom.badRequest(`Invalid response. ${validationError.message}`); + } else { + this.logger.warn(`Invalid response. ${validationError.message}`); + } + } + + // Validate the response and DOWN transform to the request version + const { value, error: resultError } = transforms.search.out.result.down< + DashboardSearchOut, + DashboardSearchOut + >( + response, + undefined, // do not override version + { validate: false } // validation is done above + ); + + if (resultError) { + throw Boom.badRequest(`Invalid response. ${resultError.message}`); + } + + return value; } } diff --git a/src/plugins/dashboard/server/content_management/index.ts b/src/plugins/dashboard/server/content_management/index.ts index 653924191267..8ff43345aa9c 100644 --- a/src/plugins/dashboard/server/content_management/index.ts +++ b/src/plugins/dashboard/server/content_management/index.ts @@ -7,4 +7,24 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +export type { + ControlGroupAttributes, + GridData, + DashboardPanel, + DashboardAttributes, + DashboardItem, + DashboardGetIn, + DashboardGetOut, + DashboardCreateIn, + DashboardCreateOut, + DashboardCreateOptions, + DashboardSearchIn, + DashboardSearchOut, + DashboardSearchOptions, + DashboardUpdateIn, + DashboardUpdateOut, + DashboardUpdateOptions, + DashboardOptions, +} from './latest'; + export { DashboardStorage } from './dashboard_storage'; diff --git a/src/plugins/dashboard/common/content_management/latest.ts b/src/plugins/dashboard/server/content_management/latest.ts similarity index 91% rename from src/plugins/dashboard/common/content_management/latest.ts rename to src/plugins/dashboard/server/content_management/latest.ts index 82b84de84f8b..e35d4011f84f 100644 --- a/src/plugins/dashboard/common/content_management/latest.ts +++ b/src/plugins/dashboard/server/content_management/latest.ts @@ -7,5 +7,5 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -// Latest version is 2 -export * from './v2'; +// Latest version is 3 +export * from './v3'; diff --git a/src/plugins/dashboard/server/content_management/schema/v1/cm_services.ts b/src/plugins/dashboard/server/content_management/v1/cm_services.ts similarity index 61% rename from src/plugins/dashboard/server/content_management/schema/v1/cm_services.ts rename to src/plugins/dashboard/server/content_management/v1/cm_services.ts index f54cf0add822..0cee0bb23f45 100644 --- a/src/plugins/dashboard/server/content_management/schema/v1/cm_services.ts +++ b/src/plugins/dashboard/server/content_management/v1/cm_services.ts @@ -16,51 +16,7 @@ import { updateOptionsSchema, createResultSchema, } from '@kbn/content-management-utils'; - -export const controlGroupInputSchema = schema - .object({ - panelsJSON: schema.maybe(schema.string()), - controlStyle: schema.maybe(schema.string()), - chainingSystem: schema.maybe(schema.string()), - ignoreParentSettingsJSON: schema.maybe(schema.string()), - }) - .extends({}, { unknowns: 'ignore' }); - -export const dashboardAttributesSchema = schema.object( - { - // General - title: schema.string(), - description: schema.string({ defaultValue: '' }), - - // Search - kibanaSavedObjectMeta: schema.object({ - searchSourceJSON: schema.maybe(schema.string()), - }), - - // Time - timeRestore: schema.maybe(schema.boolean()), - timeFrom: schema.maybe(schema.string()), - timeTo: schema.maybe(schema.string()), - refreshInterval: schema.maybe( - schema.object({ - pause: schema.boolean(), - value: schema.number(), - display: schema.maybe(schema.string()), - section: schema.maybe(schema.number()), - }) - ), - - // Dashboard Content - controlGroupInput: schema.maybe(controlGroupInputSchema), - panelsJSON: schema.string({ defaultValue: '[]' }), - optionsJSON: schema.string({ defaultValue: '{}' }), - - // Legacy - hits: schema.maybe(schema.number()), - version: schema.maybe(schema.number()), - }, - { unknowns: 'forbid' } -); +import { dashboardAttributesSchema } from '../../dashboard_saved_object/schema/v1'; export const dashboardSavedObjectSchema = savedObjectSchema(dashboardAttributesSchema); @@ -84,8 +40,10 @@ const dashboardUpdateOptionsSchema = schema.object({ mergeAttributes: schema.maybe(updateOptionsSchema.mergeAttributes), }); -// Content management service definition. -// We need it for BWC support between different versions of the content +/** + * Content management service definition v1. + * Dashboard attributes in content management version v1 are tightly coupled with the v1 model version saved object schema. + */ export const serviceDefinition: ServicesDefinition = { get: { out: { diff --git a/src/plugins/dashboard/server/content_management/v1/index.ts b/src/plugins/dashboard/server/content_management/v1/index.ts new file mode 100644 index 000000000000..163b952218bc --- /dev/null +++ b/src/plugins/dashboard/server/content_management/v1/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", 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". + */ + +export { serviceDefinition } from './cm_services'; diff --git a/src/plugins/dashboard/server/content_management/schema/v2/cm_services.ts b/src/plugins/dashboard/server/content_management/v2/cm_services.ts similarity index 70% rename from src/plugins/dashboard/server/content_management/schema/v2/cm_services.ts rename to src/plugins/dashboard/server/content_management/v2/cm_services.ts index 9e81945e4c71..3b560b841673 100644 --- a/src/plugins/dashboard/server/content_management/schema/v2/cm_services.ts +++ b/src/plugins/dashboard/server/content_management/v2/cm_services.ts @@ -7,36 +7,23 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { schema } from '@kbn/config-schema'; import { createResultSchema, objectTypeToGetResultSchema, savedObjectSchema, } from '@kbn/content-management-utils'; import type { ContentManagementServicesDefinition as ServicesDefinition } from '@kbn/object-versioning'; -import { - controlGroupInputSchema as controlGroupInputSchemaV1, - dashboardAttributesSchema as dashboardAttributesSchemaV1, - serviceDefinition as serviceDefinitionV1, -} from '../v1'; - -export const dashboardAttributesSchema = dashboardAttributesSchemaV1.extends( - { - controlGroupInput: schema.maybe( - controlGroupInputSchemaV1.extends( - { - showApplySelections: schema.maybe(schema.boolean()), - }, - { unknowns: 'ignore' } - ) - ), - }, - { unknowns: 'ignore' } -); +import type { DashboardCrudTypes } from '../../../common/content_management/v2'; +import { serviceDefinition as serviceDefinitionV1 } from '../v1'; +import { dashboardAttributesOut as attributesTov3 } from '../v3'; +import { dashboardAttributesSchema } from '../../dashboard_saved_object/schema/v2'; export const dashboardSavedObjectSchema = savedObjectSchema(dashboardAttributesSchema); -// Content management service definition. +/** + * Content management service definition v2. + * Dashboard attributes in content management version v2 are tightly coupled with the v2 model version saved object schema. + */ export const serviceDefinition: ServicesDefinition = { get: { out: { @@ -50,6 +37,7 @@ export const serviceDefinition: ServicesDefinition = { ...serviceDefinitionV1?.create?.in, data: { schema: dashboardAttributesSchema, + up: (data: DashboardCrudTypes['CreateIn']['data']) => attributesTov3(data), }, }, out: { @@ -63,6 +51,7 @@ export const serviceDefinition: ServicesDefinition = { ...serviceDefinitionV1.update?.in, data: { schema: dashboardAttributesSchema, + up: (data: DashboardCrudTypes['UpdateIn']['data']) => attributesTov3(data), }, }, }, diff --git a/src/plugins/dashboard/server/content_management/v2/index.ts b/src/plugins/dashboard/server/content_management/v2/index.ts new file mode 100644 index 000000000000..163b952218bc --- /dev/null +++ b/src/plugins/dashboard/server/content_management/v2/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", 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". + */ + +export { serviceDefinition } from './cm_services'; diff --git a/src/plugins/dashboard/server/content_management/v3/cm_services.ts b/src/plugins/dashboard/server/content_management/v3/cm_services.ts new file mode 100644 index 000000000000..e086d1cc1460 --- /dev/null +++ b/src/plugins/dashboard/server/content_management/v3/cm_services.ts @@ -0,0 +1,539 @@ +/* + * Copyright 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 { v4 as uuidv4 } from 'uuid'; +import { schema, Type } from '@kbn/config-schema'; +import { createOptionsSchemas, updateOptionsSchema } from '@kbn/content-management-utils'; +import type { ContentManagementServicesDefinition as ServicesDefinition } from '@kbn/object-versioning'; +import { + type ControlGroupChainingSystem, + type ControlLabelPosition, + type ControlWidth, + CONTROL_CHAINING_OPTIONS, + CONTROL_LABEL_POSITION_OPTIONS, + CONTROL_WIDTH_OPTIONS, + DEFAULT_CONTROL_CHAINING, + DEFAULT_CONTROL_GROW, + DEFAULT_CONTROL_LABEL_POSITION, + DEFAULT_CONTROL_WIDTH, + DEFAULT_IGNORE_PARENT_SETTINGS, + DEFAULT_AUTO_APPLY_SELECTIONS, +} from '@kbn/controls-plugin/common'; +import { FilterStateStore } from '@kbn/es-query'; +import { SortDirection } from '@kbn/data-plugin/common/search'; +import { + DASHBOARD_GRID_COLUMN_COUNT, + DEFAULT_PANEL_HEIGHT, + DEFAULT_PANEL_WIDTH, + DEFAULT_DASHBOARD_OPTIONS, +} from '../../../common/content_management'; +import { getResultV3ToV2 } from './transform_utils'; + +const apiError = schema.object({ + error: schema.string(), + message: schema.string(), + statusCode: schema.number(), + metadata: schema.maybe(schema.object({}, { unknowns: 'allow' })), +}); + +// This schema should be provided by the controls plugin. Perhaps we can resolve this with the embeddable registry. +// See https://github.com/elastic/kibana/issues/192622 +export const controlGroupInputSchema = schema.object({ + controls: schema.arrayOf( + schema.object( + { + type: schema.string({ meta: { description: 'The type of the control panel.' } }), + controlConfig: schema.maybe(schema.recordOf(schema.string(), schema.any())), + id: schema.string({ + defaultValue: uuidv4(), + meta: { description: 'The unique ID of the control.' }, + }), + order: schema.number({ + meta: { + description: 'The order of the control panel in the control group.', + }, + }), + width: schema.oneOf( + Object.values(CONTROL_WIDTH_OPTIONS).map((value) => schema.literal(value)) as [ + Type + ], + { + defaultValue: DEFAULT_CONTROL_WIDTH, + meta: { description: 'Minimum width of the control panel in the control group.' }, + } + ), + grow: schema.boolean({ + defaultValue: DEFAULT_CONTROL_GROW, + meta: { description: 'Expand width of the control panel to fit available space.' }, + }), + }, + { unknowns: 'allow' } + ), + { + defaultValue: [], + meta: { description: 'An array of control panels and their state in the control group.' }, + } + ), + labelPosition: schema.oneOf( + Object.values(CONTROL_LABEL_POSITION_OPTIONS).map((value) => schema.literal(value)) as [ + Type + ], + { + defaultValue: DEFAULT_CONTROL_LABEL_POSITION, + meta: { + description: 'Position of the labels for controls. For example, "oneLine", "twoLine".', + }, + } + ), + chainingSystem: schema.oneOf( + Object.values(CONTROL_CHAINING_OPTIONS).map((value) => schema.literal(value)) as [ + Type + ], + { + defaultValue: DEFAULT_CONTROL_CHAINING, + meta: { + description: + 'The chaining strategy for multiple controls. For example, "HIERARCHICAL" or "NONE".', + }, + } + ), + enhancements: schema.maybe(schema.recordOf(schema.string(), schema.any())), + ignoreParentSettings: schema.object({ + ignoreFilters: schema.boolean({ + meta: { description: 'Ignore global filters in controls.' }, + defaultValue: DEFAULT_IGNORE_PARENT_SETTINGS.ignoreFilters, + }), + ignoreQuery: schema.boolean({ + meta: { description: 'Ignore the global query bar in controls.' }, + defaultValue: DEFAULT_IGNORE_PARENT_SETTINGS.ignoreQuery, + }), + ignoreTimerange: schema.boolean({ + meta: { description: 'Ignore the global time range in controls.' }, + defaultValue: DEFAULT_IGNORE_PARENT_SETTINGS.ignoreTimerange, + }), + ignoreValidations: schema.boolean({ + meta: { description: 'Ignore validations in controls.' }, + defaultValue: DEFAULT_IGNORE_PARENT_SETTINGS.ignoreValidations, + }), + }), + autoApplySelections: schema.boolean({ + meta: { description: 'Show apply selections button in controls.' }, + defaultValue: DEFAULT_AUTO_APPLY_SELECTIONS, + }), +}); + +const searchSourceSchema = schema.object( + { + type: schema.maybe(schema.string()), + query: schema.maybe( + schema.object({ + query: schema.oneOf([ + schema.string({ + meta: { + description: + 'A text-based query such as Kibana Query Language (KQL) or Lucene query language.', + }, + }), + schema.recordOf(schema.string(), schema.any()), + ]), + language: schema.string({ + meta: { description: 'The query language such as KQL or Lucene.' }, + }), + }) + ), + filter: schema.maybe( + schema.arrayOf( + schema.object( + { + meta: schema.object( + { + alias: schema.maybe(schema.nullable(schema.string())), + disabled: schema.maybe(schema.boolean()), + negate: schema.maybe(schema.boolean()), + controlledBy: schema.maybe(schema.string()), + group: schema.maybe(schema.string()), + index: schema.maybe(schema.string()), + isMultiIndex: schema.maybe(schema.boolean()), + type: schema.maybe(schema.string()), + key: schema.maybe(schema.string()), + params: schema.maybe(schema.any()), + value: schema.maybe(schema.string()), + field: schema.maybe(schema.string()), + }, + { unknowns: 'allow' } + ), + query: schema.maybe(schema.recordOf(schema.string(), schema.any())), + $state: schema.maybe( + schema.object({ + store: schema.oneOf( + [ + schema.literal(FilterStateStore.APP_STATE), + schema.literal(FilterStateStore.GLOBAL_STATE), + ], + { + meta: { + description: + "Denote whether a filter is specific to an application's context (e.g. 'appState') or whether it should be applied globally (e.g. 'globalState').", + }, + } + ), + }) + ), + }, + { meta: { description: 'A filter for the search source.' } } + ) + ) + ), + sort: schema.maybe( + schema.arrayOf( + schema.recordOf( + schema.string(), + schema.oneOf([ + schema.oneOf([schema.literal(SortDirection.asc), schema.literal(SortDirection.desc)]), + schema.object({ + order: schema.oneOf([ + schema.literal(SortDirection.asc), + schema.literal(SortDirection.desc), + ]), + format: schema.maybe(schema.string()), + }), + schema.object({ + order: schema.oneOf([ + schema.literal(SortDirection.asc), + schema.literal(SortDirection.desc), + ]), + numeric_type: schema.maybe( + schema.oneOf([ + schema.literal('double'), + schema.literal('long'), + schema.literal('date'), + schema.literal('date_nanos'), + ]) + ), + }), + ]) + ) + ) + ), + }, + /** + The Dashboard _should_ only ever uses the query and filters fields on the search + source. But we should be liberal in what we accept, so we allow unknowns. + */ + { defaultValue: {}, unknowns: 'allow' } +); + +export const gridDataSchema = schema.object({ + x: schema.number({ meta: { description: 'The x coordinate of the panel in grid units' } }), + y: schema.number({ meta: { description: 'The y coordinate of the panel in grid units' } }), + w: schema.number({ + defaultValue: DEFAULT_PANEL_WIDTH, + min: 1, + max: DASHBOARD_GRID_COLUMN_COUNT, + meta: { description: 'The width of the panel in grid units' }, + }), + h: schema.number({ + defaultValue: DEFAULT_PANEL_HEIGHT, + min: 1, + meta: { description: 'The height of the panel in grid units' }, + }), + i: schema.string({ + meta: { description: 'The unique identifier of the panel' }, + defaultValue: uuidv4(), + }), +}); + +export const panelSchema = schema.object({ + panelConfig: schema.object( + { + version: schema.maybe( + schema.string({ + meta: { description: 'The version of the embeddable in the panel.' }, + }) + ), + title: schema.maybe(schema.string({ meta: { description: 'The title of the panel' } })), + description: schema.maybe( + schema.string({ meta: { description: 'The description of the panel' } }) + ), + savedObjectId: schema.maybe( + schema.string({ + meta: { description: 'The unique id of the library item to construct the embeddable.' }, + }) + ), + hidePanelTitles: schema.maybe( + schema.boolean({ + defaultValue: false, + meta: { description: 'Set to true to hide the panel title in its container.' }, + }) + ), + enhancements: schema.maybe(schema.recordOf(schema.string(), schema.any())), + }, + { + unknowns: 'allow', + } + ), + id: schema.maybe( + schema.string({ meta: { description: 'The saved object id for by reference panels' } }) + ), + type: schema.string({ meta: { description: 'The embeddable type' } }), + panelRefName: schema.maybe(schema.string()), + gridData: gridDataSchema, + panelIndex: schema.string({ + meta: { description: 'The unique ID of the panel.' }, + defaultValue: schema.siblingRef('gridData.i'), + }), + title: schema.maybe(schema.string({ meta: { description: 'The title of the panel' } })), + version: schema.maybe( + schema.string({ + meta: { + description: + "The version was used to store Kibana version information from versions 7.3.0 -> 8.11.0. As of version 8.11.0, the versioning information is now per-embeddable-type and is stored on the embeddable's input. (panelConfig in this type).", + deprecated: true, + }, + }) + ), +}); + +export const optionsSchema = schema.object({ + hidePanelTitles: schema.boolean({ + defaultValue: DEFAULT_DASHBOARD_OPTIONS.hidePanelTitles, + meta: { description: 'Hide the panel titles in the dashboard.' }, + }), + useMargins: schema.boolean({ + defaultValue: DEFAULT_DASHBOARD_OPTIONS.useMargins, + meta: { description: 'Show margins between panels in the dashboard layout.' }, + }), + syncColors: schema.boolean({ + defaultValue: DEFAULT_DASHBOARD_OPTIONS.syncColors, + meta: { description: 'Synchronize colors between related panels in the dashboard.' }, + }), + syncTooltips: schema.boolean({ + defaultValue: DEFAULT_DASHBOARD_OPTIONS.syncTooltips, + meta: { description: 'Synchronize tooltips between related panels in the dashboard.' }, + }), + syncCursor: schema.boolean({ + defaultValue: DEFAULT_DASHBOARD_OPTIONS.syncCursor, + meta: { description: 'Synchronize cursor position between related panels in the dashboard.' }, + }), +}); + +// These are the attributes that are returned in search results +export const searchResultsAttributesSchema = schema.object({ + title: schema.string({ meta: { description: 'A human-readable title for the dashboard' } }), + description: schema.string({ defaultValue: '', meta: { description: 'A short description.' } }), + timeRestore: schema.boolean({ + defaultValue: false, + meta: { description: 'Whether to restore time upon viewing this dashboard' }, + }), +}); + +export const dashboardAttributesSchema = searchResultsAttributesSchema.extends({ + // Search + kibanaSavedObjectMeta: schema.object( + { + searchSource: schema.maybe(searchSourceSchema), + }, + { + meta: { + description: 'A container for various metadata', + }, + defaultValue: {}, + } + ), + // Time + timeFrom: schema.maybe( + schema.string({ meta: { description: 'An ISO string indicating when to restore time from' } }) + ), + timeTo: schema.maybe( + schema.string({ meta: { description: 'An ISO string indicating when to restore time from' } }) + ), + refreshInterval: schema.maybe( + schema.object( + { + pause: schema.boolean({ + meta: { + description: + 'Whether the refresh interval is set to be paused while viewing the dashboard.', + }, + }), + value: schema.number({ + meta: { + description: 'A numeric value indicating refresh frequency in milliseconds.', + }, + }), + display: schema.maybe( + schema.string({ + meta: { + description: + 'A human-readable string indicating the refresh frequency. No longer used.', + deprecated: true, + }, + }) + ), + section: schema.maybe( + schema.number({ + meta: { + description: 'No longer used.', // TODO what is this legacy property? + deprecated: true, + }, + }) + ), + }, + { + meta: { + description: 'A container for various refresh interval settings', + }, + } + ) + ), + + // Dashboard Content + controlGroupInput: schema.maybe(controlGroupInputSchema), + panels: schema.arrayOf(panelSchema, { defaultValue: [] }), + options: optionsSchema, + version: schema.maybe(schema.number({ meta: { deprecated: true } })), +}); + +export const referenceSchema = schema.object( + { + name: schema.string(), + type: schema.string(), + id: schema.string(), + }, + { unknowns: 'forbid' } +); + +export const dashboardItemSchema = schema.object( + { + id: schema.string(), + type: schema.string(), + version: schema.maybe(schema.string()), + createdAt: schema.maybe(schema.string()), + updatedAt: schema.maybe(schema.string()), + createdBy: schema.maybe(schema.string()), + updatedBy: schema.maybe(schema.string()), + managed: schema.maybe(schema.boolean()), + error: schema.maybe(apiError), + attributes: dashboardAttributesSchema, + references: schema.arrayOf(referenceSchema), + namespaces: schema.maybe(schema.arrayOf(schema.string())), + originId: schema.maybe(schema.string()), + }, + { unknowns: 'allow' } +); + +export const dashboardSearchResultsSchema = dashboardItemSchema.extends({ + attributes: searchResultsAttributesSchema, +}); + +export const dashboardSearchOptionsSchema = schema.maybe( + schema.object( + { + onlyTitle: schema.maybe(schema.boolean()), + fields: schema.maybe(schema.arrayOf(schema.string())), + kuery: schema.maybe(schema.string()), + cursor: schema.maybe(schema.number()), + limit: schema.maybe(schema.number()), + }, + { unknowns: 'forbid' } + ) +); + +export const dashboardCreateOptionsSchema = schema.object({ + id: schema.maybe(createOptionsSchemas.id), + overwrite: schema.maybe(createOptionsSchemas.overwrite), + references: schema.maybe(schema.arrayOf(referenceSchema)), + initialNamespaces: schema.maybe(createOptionsSchemas.initialNamespaces), +}); + +export const dashboardUpdateOptionsSchema = schema.object({ + references: schema.maybe(schema.arrayOf(referenceSchema)), + mergeAttributes: schema.maybe(updateOptionsSchema.mergeAttributes), +}); + +export const dashboardGetResultSchema = schema.object( + { + item: dashboardItemSchema, + meta: schema.object( + { + outcome: schema.oneOf([ + schema.literal('exactMatch'), + schema.literal('aliasMatch'), + schema.literal('conflict'), + ]), + aliasTargetId: schema.maybe(schema.string()), + aliasPurpose: schema.maybe( + schema.oneOf([ + schema.literal('savedObjectConversion'), + schema.literal('savedObjectImport'), + ]) + ), + }, + { unknowns: 'forbid' } + ), + }, + { unknowns: 'forbid' } +); + +export const dashboardCreateResultSchema = schema.object( + { + item: dashboardItemSchema, + }, + { unknowns: 'forbid' } +); + +export const serviceDefinition: ServicesDefinition = { + get: { + out: { + result: { + schema: dashboardGetResultSchema, + down: getResultV3ToV2, + }, + }, + }, + create: { + in: { + options: { + schema: dashboardCreateOptionsSchema, + }, + data: { + schema: dashboardAttributesSchema, + }, + }, + out: { + result: { + schema: dashboardCreateResultSchema, + }, + }, + }, + update: { + in: { + options: { + schema: dashboardUpdateOptionsSchema, + }, + data: { + schema: dashboardAttributesSchema, + }, + }, + }, + search: { + in: { + options: { + schema: dashboardSearchOptionsSchema, + }, + }, + }, + mSearch: { + out: { + result: { + schema: dashboardItemSchema, + }, + }, + }, +}; diff --git a/src/plugins/dashboard/server/content_management/v3/index.ts b/src/plugins/dashboard/server/content_management/v3/index.ts new file mode 100644 index 000000000000..7be9313c3210 --- /dev/null +++ b/src/plugins/dashboard/server/content_management/v3/index.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", 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". + */ + +export type { + ControlGroupAttributes, + GridData, + DashboardPanel, + DashboardAttributes, + DashboardItem, + DashboardGetIn, + DashboardGetOut, + DashboardCreateIn, + DashboardCreateOut, + DashboardCreateOptions, + DashboardSearchIn, + DashboardSearchOut, + DashboardSearchOptions, + DashboardUpdateIn, + DashboardUpdateOut, + DashboardUpdateOptions, + DashboardOptions, +} from './types'; +export { + serviceDefinition, + dashboardAttributesSchema, + dashboardGetResultSchema, + dashboardCreateResultSchema, + dashboardItemSchema, + dashboardSearchResultsSchema, + referenceSchema, +} from './cm_services'; +export { + dashboardAttributesOut, + itemAttrsToSavedObjectAttrs, + savedObjectToItem, +} from './transform_utils'; diff --git a/src/plugins/dashboard/server/content_management/v3/transform_utils.test.ts b/src/plugins/dashboard/server/content_management/v3/transform_utils.test.ts new file mode 100644 index 000000000000..627f1c421103 --- /dev/null +++ b/src/plugins/dashboard/server/content_management/v3/transform_utils.test.ts @@ -0,0 +1,551 @@ +/* + * Copyright 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 { SavedObject } from '@kbn/core-saved-objects-api-server'; +import type { + DashboardSavedObjectAttributes, + SavedDashboardPanel, +} from '../../dashboard_saved_object'; +import type { DashboardAttributes, DashboardItem } from './types'; +import { + dashboardAttributesOut, + getResultV3ToV2, + itemAttrsToSavedObjectAttrs, + savedObjectToItem, +} from './transform_utils'; +import { + DEFAULT_AUTO_APPLY_SELECTIONS, + DEFAULT_CONTROL_CHAINING, + DEFAULT_CONTROL_GROW, + DEFAULT_CONTROL_LABEL_POSITION, + DEFAULT_CONTROL_WIDTH, + DEFAULT_IGNORE_PARENT_SETTINGS, + ControlLabelPosition, + ControlGroupChainingSystem, + ControlWidth, +} from '@kbn/controls-plugin/common'; +import { DEFAULT_DASHBOARD_OPTIONS } from '../../../common/content_management'; + +describe('dashboardAttributesOut', () => { + const controlGroupInputControlsSo = { + explicitInput: { anyKey: 'some value' }, + type: 'type1', + order: 0, + }; + + const panelsSo: SavedDashboardPanel[] = [ + { + embeddableConfig: { enhancements: {} }, + gridData: { x: 0, y: 0, w: 10, h: 10, i: '1' }, + id: '1', + panelIndex: '1', + panelRefName: 'ref1', + title: 'title1', + type: 'type1', + version: '2', + }, + ]; + + it('should set default values if not provided', () => { + const input: DashboardSavedObjectAttributes = { + controlGroupInput: { + panelsJSON: JSON.stringify({ foo: controlGroupInputControlsSo }), + }, + panelsJSON: JSON.stringify(panelsSo), + optionsJSON: JSON.stringify({ + hidePanelTitles: false, + }), + kibanaSavedObjectMeta: {}, + title: 'my title', + description: 'my description', + }; + expect(dashboardAttributesOut(input)).toEqual({ + controlGroupInput: { + chainingSystem: DEFAULT_CONTROL_CHAINING, + labelPosition: DEFAULT_CONTROL_LABEL_POSITION, + ignoreParentSettings: DEFAULT_IGNORE_PARENT_SETTINGS, + autoApplySelections: DEFAULT_AUTO_APPLY_SELECTIONS, + controls: [ + { + controlConfig: { anyKey: 'some value' }, + grow: DEFAULT_CONTROL_GROW, + id: 'foo', + order: 0, + type: 'type1', + width: DEFAULT_CONTROL_WIDTH, + }, + ], + }, + description: 'my description', + kibanaSavedObjectMeta: {}, + options: { + ...DEFAULT_DASHBOARD_OPTIONS, + hidePanelTitles: false, + }, + panels: [ + { + panelConfig: { enhancements: {} }, + gridData: { x: 0, y: 0, w: 10, h: 10, i: '1' }, + id: '1', + panelIndex: '1', + panelRefName: 'ref1', + title: 'title1', + type: 'type1', + version: '2', + }, + ], + timeRestore: false, + title: 'my title', + }); + }); + + it('should transform full attributes correctly', () => { + const input: DashboardSavedObjectAttributes = { + controlGroupInput: { + panelsJSON: JSON.stringify({ + foo: { + ...controlGroupInputControlsSo, + grow: false, + width: 'small', + }, + }), + ignoreParentSettingsJSON: JSON.stringify({ ignoreFilters: true }), + controlStyle: 'twoLine', + chainingSystem: 'NONE', + showApplySelections: true, + }, + description: 'description', + kibanaSavedObjectMeta: { + searchSourceJSON: JSON.stringify({ query: { query: 'test', language: 'KQL' } }), + }, + optionsJSON: JSON.stringify({ + hidePanelTitles: true, + useMargins: false, + syncColors: false, + syncTooltips: false, + syncCursor: false, + }), + panelsJSON: JSON.stringify(panelsSo), + refreshInterval: { pause: true, value: 1000 }, + timeFrom: 'now-15m', + timeRestore: true, + timeTo: 'now', + title: 'title', + }; + expect(dashboardAttributesOut(input)).toEqual({ + controlGroupInput: { + chainingSystem: 'NONE', + labelPosition: 'twoLine', + ignoreParentSettings: { + ignoreFilters: true, + ignoreQuery: false, + ignoreTimerange: false, + ignoreValidations: false, + }, + autoApplySelections: false, + controls: [ + { + controlConfig: { + anyKey: 'some value', + }, + id: 'foo', + grow: false, + width: 'small', + order: 0, + type: 'type1', + }, + ], + }, + description: 'description', + kibanaSavedObjectMeta: { + searchSource: { query: { query: 'test', language: 'KQL' } }, + }, + options: { + hidePanelTitles: true, + useMargins: false, + syncColors: false, + syncTooltips: false, + syncCursor: false, + }, + panels: [ + { + panelConfig: { + enhancements: {}, + }, + gridData: { + x: 0, + y: 0, + w: 10, + h: 10, + i: '1', + }, + id: '1', + panelIndex: '1', + panelRefName: 'ref1', + title: 'title1', + type: 'type1', + version: '2', + }, + ], + refreshInterval: { + pause: true, + value: 1000, + }, + timeFrom: 'now-15m', + timeRestore: true, + timeTo: 'now', + title: 'title', + }); + }); +}); + +describe('itemAttrsToSavedObjectAttrs', () => { + it('should transform item attributes to saved object attributes correctly', () => { + const input: DashboardAttributes = { + controlGroupInput: { + chainingSystem: 'NONE', + labelPosition: 'twoLine', + controls: [ + { + controlConfig: { anyKey: 'some value' }, + grow: false, + id: 'foo', + order: 0, + type: 'type1', + width: 'small', + }, + ], + ignoreParentSettings: { + ignoreFilters: true, + ignoreQuery: true, + ignoreTimerange: true, + ignoreValidations: true, + }, + autoApplySelections: false, + }, + description: 'description', + kibanaSavedObjectMeta: { searchSource: { query: { query: 'test', language: 'KQL' } } }, + options: { + hidePanelTitles: true, + useMargins: false, + syncColors: false, + syncTooltips: false, + syncCursor: false, + }, + panels: [ + { + gridData: { x: 0, y: 0, w: 10, h: 10, i: '1' }, + id: '1', + panelConfig: { enhancements: {} }, + panelIndex: '1', + panelRefName: 'ref1', + title: 'title1', + type: 'type1', + version: '2', + }, + ], + timeRestore: true, + title: 'title', + refreshInterval: { pause: true, value: 1000 }, + timeFrom: 'now-15m', + timeTo: 'now', + }; + + const output = itemAttrsToSavedObjectAttrs(input); + expect(output).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "controlGroupInput": Object { + "chainingSystem": "NONE", + "controlStyle": "twoLine", + "ignoreParentSettingsJSON": "{\\"ignoreFilters\\":true,\\"ignoreQuery\\":true,\\"ignoreTimerange\\":true,\\"ignoreValidations\\":true}", + "panelsJSON": "{\\"foo\\":{\\"grow\\":false,\\"order\\":0,\\"type\\":\\"type1\\",\\"width\\":\\"small\\",\\"explicitInput\\":{\\"anyKey\\":\\"some value\\",\\"id\\":\\"foo\\"}}}", + "showApplySelections": true, + }, + "description": "description", + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{\\"query\\":{\\"query\\":\\"test\\",\\"language\\":\\"KQL\\"}}", + }, + "optionsJSON": "{\\"hidePanelTitles\\":true,\\"useMargins\\":false,\\"syncColors\\":false,\\"syncTooltips\\":false,\\"syncCursor\\":false}", + "panelsJSON": "[{\\"id\\":\\"1\\",\\"panelRefName\\":\\"ref1\\",\\"title\\":\\"title1\\",\\"type\\":\\"type1\\",\\"version\\":\\"2\\",\\"embeddableConfig\\":{\\"enhancements\\":{}},\\"panelIndex\\":\\"1\\",\\"gridData\\":{\\"x\\":0,\\"y\\":0,\\"w\\":10,\\"h\\":10,\\"i\\":\\"1\\"}}]", + "refreshInterval": Object { + "pause": true, + "value": 1000, + }, + "timeFrom": "now-15m", + "timeRestore": true, + "timeTo": "now", + "title": "title", + }, + "error": null, + } + `); + }); + + it('should handle missing optional attributes', () => { + const input: DashboardAttributes = { + title: 'title', + description: 'my description', + timeRestore: false, + panels: [], + options: DEFAULT_DASHBOARD_OPTIONS, + kibanaSavedObjectMeta: {}, + }; + + const output = itemAttrsToSavedObjectAttrs(input); + expect(output).toMatchInlineSnapshot(` + Object { + "attributes": Object { + "description": "my description", + "kibanaSavedObjectMeta": Object { + "searchSourceJSON": "{}", + }, + "optionsJSON": "{\\"hidePanelTitles\\":false,\\"useMargins\\":true,\\"syncColors\\":true,\\"syncCursor\\":true,\\"syncTooltips\\":true}", + "panelsJSON": "[]", + "timeRestore": false, + "title": "title", + }, + "error": null, + } + `); + }); +}); + +describe('savedObjectToItem', () => { + const commonSavedObject: SavedObject = { + references: [], + id: '3d8459d9-0f1a-403d-aa82-6d93713a54b5', + type: 'dashboard', + attributes: {}, + }; + + const getSavedObjectForAttributes = ( + attributes: DashboardSavedObjectAttributes + ): SavedObject => { + return { + ...commonSavedObject, + attributes, + }; + }; + it('should convert saved object to item with all attributes', () => { + const input = getSavedObjectForAttributes({ + title: 'title', + description: 'description', + timeRestore: true, + panelsJSON: JSON.stringify([ + { + embeddableConfig: { enhancements: {} }, + gridData: { x: 0, y: 0, w: 10, h: 10, i: '1' }, + id: '1', + panelIndex: '1', + panelRefName: 'ref1', + title: 'title1', + type: 'type1', + version: '2', + }, + ]), + optionsJSON: JSON.stringify({ + hidePanelTitles: true, + useMargins: false, + syncColors: false, + syncTooltips: false, + syncCursor: false, + }), + kibanaSavedObjectMeta: { + searchSourceJSON: '{"query":{"query":"test","language":"KQL"}}', + }, + }); + + const { item, error } = savedObjectToItem(input, false); + expect(error).toBeNull(); + expect(item).toEqual({ + ...commonSavedObject, + attributes: { + title: 'title', + description: 'description', + timeRestore: true, + panels: [ + { + panelConfig: { enhancements: {} }, + gridData: { x: 0, y: 0, w: 10, h: 10, i: '1' }, + id: '1', + panelIndex: '1', + panelRefName: 'ref1', + title: 'title1', + type: 'type1', + version: '2', + }, + ], + options: { + hidePanelTitles: true, + useMargins: false, + syncColors: false, + syncTooltips: false, + syncCursor: false, + }, + kibanaSavedObjectMeta: { + searchSource: { query: { query: 'test', language: 'KQL' } }, + }, + }, + }); + }); + + it('should handle missing optional attributes', () => { + const input = getSavedObjectForAttributes({ + title: 'title', + description: 'description', + timeRestore: false, + panelsJSON: '[]', + optionsJSON: '{}', + kibanaSavedObjectMeta: {}, + }); + + const { item, error } = savedObjectToItem(input, false); + expect(error).toBeNull(); + expect(item).toEqual({ + ...commonSavedObject, + attributes: { + title: 'title', + description: 'description', + timeRestore: false, + panels: [], + options: DEFAULT_DASHBOARD_OPTIONS, + kibanaSavedObjectMeta: {}, + }, + }); + }); + + it('should handle partial saved object', () => { + const input = { + ...commonSavedObject, + references: undefined, + attributes: { + title: 'title', + description: 'my description', + timeRestore: false, + }, + }; + + const { item, error } = savedObjectToItem(input, true, ['title', 'description']); + expect(error).toBeNull(); + expect(item).toEqual({ + ...commonSavedObject, + references: undefined, + attributes: { + title: 'title', + description: 'my description', + }, + }); + }); + + it('should return an error if attributes can not be parsed', () => { + const input = { + ...commonSavedObject, + references: undefined, + attributes: { + title: 'title', + panelsJSON: 'not stringified json', + }, + }; + const { item, error } = savedObjectToItem(input, true); + expect(item).toBeNull(); + expect(error).not.toBe(null); + }); +}); + +describe('getResultV3ToV2', () => { + const commonAttributes = { + description: 'description', + refreshInterval: { pause: true, value: 1000 }, + timeFrom: 'now-15m', + timeRestore: true, + timeTo: 'now', + title: 'title', + }; + it('should transform a v3 result to a v2 result with all attributes', () => { + const v3Result = { + meta: { outcome: 'exactMatch' as const }, + item: { + id: '1', + type: 'dashboard', + attributes: { + ...commonAttributes, + controlGroupInput: { + chainingSystem: 'NONE' as ControlGroupChainingSystem, + labelPosition: 'twoLine' as ControlLabelPosition, + controls: [ + { + controlConfig: { bizz: 'buzz' }, + grow: false, + order: 0, + id: 'foo', + type: 'type1', + width: 'small' as ControlWidth, + }, + ], + ignoreParentSettings: { + ignoreFilters: true, + ignoreQuery: true, + ignoreTimerange: true, + ignoreValidations: true, + }, + autoApplySelections: false, + }, + kibanaSavedObjectMeta: { searchSource: { query: { query: 'test', language: 'KQL' } } }, + options: { + hidePanelTitles: true, + useMargins: false, + syncColors: false, + syncCursor: false, + syncTooltips: false, + }, + panels: [ + { + id: '1', + type: 'visualization', + panelConfig: { title: 'my panel' }, + gridData: { x: 0, y: 0, w: 15, h: 15, i: 'foo' }, + panelIndex: 'foo', + }, + ], + }, + references: [], + }, + }; + + const output = getResultV3ToV2(v3Result); + + // Common attributes should match between v2 and v3 + expect(output.item.attributes).toMatchObject(commonAttributes); + expect(output.item.attributes.controlGroupInput).toMatchObject({ + chainingSystem: 'NONE', + controlStyle: 'twoLine', + showApplySelections: true, + }); + + // Check transformed attributes + expect(output.item.attributes.controlGroupInput!.panelsJSON).toMatchInlineSnapshot( + `"{\\"foo\\":{\\"grow\\":false,\\"order\\":0,\\"type\\":\\"type1\\",\\"width\\":\\"small\\",\\"explicitInput\\":{\\"bizz\\":\\"buzz\\",\\"id\\":\\"foo\\"}}}"` + ); + expect( + output.item.attributes.controlGroupInput!.ignoreParentSettingsJSON + ).toMatchInlineSnapshot( + `"{\\"ignoreFilters\\":true,\\"ignoreQuery\\":true,\\"ignoreTimerange\\":true,\\"ignoreValidations\\":true}"` + ); + expect(output.item.attributes.kibanaSavedObjectMeta.searchSourceJSON).toMatchInlineSnapshot( + `"{\\"query\\":{\\"query\\":\\"test\\",\\"language\\":\\"KQL\\"}}"` + ); + expect(output.item.attributes.optionsJSON).toMatchInlineSnapshot( + `"{\\"hidePanelTitles\\":true,\\"useMargins\\":false,\\"syncColors\\":false,\\"syncCursor\\":false,\\"syncTooltips\\":false}"` + ); + expect(output.item.attributes.panelsJSON).toMatchInlineSnapshot( + `"[{\\"id\\":\\"1\\",\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{\\"title\\":\\"my panel\\"},\\"panelIndex\\":\\"foo\\",\\"gridData\\":{\\"x\\":0,\\"y\\":0,\\"w\\":15,\\"h\\":15,\\"i\\":\\"foo\\"}}]"` + ); + }); +}); diff --git a/src/plugins/dashboard/server/content_management/v3/transform_utils.ts b/src/plugins/dashboard/server/content_management/v3/transform_utils.ts new file mode 100644 index 000000000000..843dd59f849f --- /dev/null +++ b/src/plugins/dashboard/server/content_management/v3/transform_utils.ts @@ -0,0 +1,365 @@ +/* + * Copyright 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 { v4 as uuidv4 } from 'uuid'; +import { pick } from 'lodash'; + +import type { Query } from '@kbn/es-query'; +import { + type ControlGroupChainingSystem, + type ControlLabelPosition, + type ControlPanelsState, + type SerializedControlState, + DEFAULT_AUTO_APPLY_SELECTIONS, + DEFAULT_CONTROL_CHAINING, + DEFAULT_CONTROL_GROW, + DEFAULT_CONTROL_LABEL_POSITION, + DEFAULT_CONTROL_WIDTH, + DEFAULT_IGNORE_PARENT_SETTINGS, +} from '@kbn/controls-plugin/common'; +import { SerializedSearchSourceFields, parseSearchSourceJSON } from '@kbn/data-plugin/common'; + +import type { SavedObject, SavedObjectReference } from '@kbn/core-saved-objects-api-server'; +import type { + ControlGroupAttributes, + DashboardAttributes, + DashboardGetOut, + DashboardItem, + DashboardOptions, + ItemAttrsToSavedObjectAttrsReturn, + PartialDashboardItem, + SavedObjectToItemReturn, +} from './types'; +import type { + DashboardSavedObjectAttributes, + SavedDashboardPanel, +} from '../../dashboard_saved_object'; +import type { + ControlGroupAttributes as ControlGroupAttributesV2, + DashboardCrudTypes as DashboardCrudTypesV2, +} from '../../../common/content_management/v2'; +import { DEFAULT_DASHBOARD_OPTIONS } from '../../../common/content_management'; + +function controlGroupInputOut( + controlGroupInput?: DashboardSavedObjectAttributes['controlGroupInput'] +): ControlGroupAttributes | undefined { + if (!controlGroupInput) { + return; + } + const { + panelsJSON, + ignoreParentSettingsJSON, + controlStyle = DEFAULT_CONTROL_LABEL_POSITION, + chainingSystem = DEFAULT_CONTROL_CHAINING, + showApplySelections = !DEFAULT_AUTO_APPLY_SELECTIONS, + } = controlGroupInput; + const controls = panelsJSON + ? Object.entries(JSON.parse(panelsJSON) as ControlPanelsState).map( + ([ + id, + { + explicitInput, + type, + grow = DEFAULT_CONTROL_GROW, + width = DEFAULT_CONTROL_WIDTH, + order, + }, + ]) => ({ + controlConfig: explicitInput, + id, + grow, + order, + type, + width, + }) + ) + : []; + + const { + ignoreFilters = DEFAULT_IGNORE_PARENT_SETTINGS.ignoreFilters, + ignoreQuery = DEFAULT_IGNORE_PARENT_SETTINGS.ignoreQuery, + ignoreTimerange = DEFAULT_IGNORE_PARENT_SETTINGS.ignoreTimerange, + ignoreValidations = DEFAULT_IGNORE_PARENT_SETTINGS.ignoreValidations, + } = ignoreParentSettingsJSON ? JSON.parse(ignoreParentSettingsJSON) : {}; + + // try to maintain a consistent (alphabetical) order of keys + return { + autoApplySelections: !showApplySelections, + chainingSystem: chainingSystem as ControlGroupChainingSystem, + controls, + labelPosition: controlStyle as ControlLabelPosition, + ignoreParentSettings: { ignoreFilters, ignoreQuery, ignoreTimerange, ignoreValidations }, + }; +} + +function kibanaSavedObjectMetaOut( + kibanaSavedObjectMeta: DashboardSavedObjectAttributes['kibanaSavedObjectMeta'] +): DashboardAttributes['kibanaSavedObjectMeta'] { + const { searchSourceJSON } = kibanaSavedObjectMeta; + if (!searchSourceJSON) { + return {}; + } + // Dashboards do not yet support ES|QL (AggregateQuery) in the search source + return { + searchSource: parseSearchSourceJSON(searchSourceJSON) as Omit< + SerializedSearchSourceFields, + 'query' + > & { query?: Query }, + }; +} + +function optionsOut(optionsJSON: string): DashboardAttributes['options'] { + const { + hidePanelTitles = DEFAULT_DASHBOARD_OPTIONS.hidePanelTitles, + useMargins = DEFAULT_DASHBOARD_OPTIONS.useMargins, + syncColors = DEFAULT_DASHBOARD_OPTIONS.syncColors, + syncCursor = DEFAULT_DASHBOARD_OPTIONS.syncCursor, + syncTooltips = DEFAULT_DASHBOARD_OPTIONS.syncTooltips, + } = JSON.parse(optionsJSON) as DashboardOptions; + return { + hidePanelTitles, + useMargins, + syncColors, + syncCursor, + syncTooltips, + }; +} + +function panelsOut(panelsJSON: string): DashboardAttributes['panels'] { + const panels = JSON.parse(panelsJSON) as SavedDashboardPanel[]; + return panels.map( + ({ embeddableConfig, gridData, id, panelIndex, panelRefName, title, type, version }) => ({ + gridData, + id, + panelConfig: embeddableConfig, + panelIndex, + panelRefName, + title, + type, + version, + }) + ); +} + +export function dashboardAttributesOut( + attributes: DashboardSavedObjectAttributes | Partial +): DashboardAttributes | Partial { + const { + controlGroupInput, + description, + kibanaSavedObjectMeta, + optionsJSON, + panelsJSON, + refreshInterval, + timeFrom, + timeRestore, + timeTo, + title, + version, + } = attributes; + // try to maintain a consistent (alphabetical) order of keys + return { + ...(controlGroupInput && { controlGroupInput: controlGroupInputOut(controlGroupInput) }), + ...(description && { description }), + ...(kibanaSavedObjectMeta && { + kibanaSavedObjectMeta: kibanaSavedObjectMetaOut(kibanaSavedObjectMeta), + }), + ...(optionsJSON && { options: optionsOut(optionsJSON) }), + ...(panelsJSON && { panels: panelsOut(panelsJSON) }), + ...(refreshInterval && { + refreshInterval: { pause: refreshInterval.pause, value: refreshInterval.value }, + }), + ...(timeFrom && { timeFrom }), + timeRestore: timeRestore ?? false, + ...(timeTo && { timeTo }), + title, + ...(version && { version }), + }; +} + +function controlGroupInputIn( + controlGroupInput?: ControlGroupAttributes +): DashboardSavedObjectAttributes['controlGroupInput'] | undefined { + if (!controlGroupInput) { + return; + } + const { controls, ignoreParentSettings, labelPosition, chainingSystem, autoApplySelections } = + controlGroupInput; + const updatedControls = Object.fromEntries( + controls.map(({ controlConfig, id = uuidv4(), ...restOfControl }) => { + return [id, { ...restOfControl, explicitInput: { ...controlConfig, id } }]; + }) + ); + return { + chainingSystem, + controlStyle: labelPosition, + ignoreParentSettingsJSON: JSON.stringify(ignoreParentSettings), + panelsJSON: JSON.stringify(updatedControls), + showApplySelections: !autoApplySelections, + }; +} + +function panelsIn( + panels: DashboardAttributes['panels'] +): DashboardSavedObjectAttributes['panelsJSON'] { + const updatedPanels = panels.map(({ panelIndex, gridData, panelConfig, ...restPanel }) => { + const idx = panelIndex ?? uuidv4(); + return { + ...restPanel, + embeddableConfig: panelConfig, + panelIndex: idx, + gridData: { + ...gridData, + i: idx, + }, + }; + }); + + return JSON.stringify(updatedPanels); +} + +function kibanaSavedObjectMetaIn( + kibanaSavedObjectMeta: DashboardAttributes['kibanaSavedObjectMeta'] +) { + const { searchSource } = kibanaSavedObjectMeta; + return { searchSourceJSON: JSON.stringify(searchSource ?? {}) }; +} + +export const getResultV3ToV2 = (result: DashboardGetOut): DashboardCrudTypesV2['GetOut'] => { + const { meta, item } = result; + const { attributes, ...rest } = item; + const { + controlGroupInput, + description, + kibanaSavedObjectMeta, + options, + panels, + refreshInterval, + timeFrom, + timeRestore, + timeTo, + title, + version, + } = attributes; + + const v2Attributes = { + ...(controlGroupInput && { + controlGroupInput: controlGroupInputIn(controlGroupInput) as ControlGroupAttributesV2, + }), + description, + ...(kibanaSavedObjectMeta && { + kibanaSavedObjectMeta: kibanaSavedObjectMetaIn(kibanaSavedObjectMeta), + }), + ...(options && { optionsJSON: JSON.stringify(options) }), + panelsJSON: panels ? panelsIn(panels) : '[]', + refreshInterval, + ...(timeFrom && { timeFrom }), + timeRestore, + ...(timeTo && { timeTo }), + title, + ...(version && { version }), + }; + return { + meta, + item: { + ...rest, + attributes: v2Attributes, + }, + }; +}; + +export const itemAttrsToSavedObjectAttrs = ( + attributes: DashboardAttributes +): ItemAttrsToSavedObjectAttrsReturn => { + try { + const { controlGroupInput, kibanaSavedObjectMeta, options, panels, ...rest } = attributes; + const soAttributes = { + ...rest, + ...(controlGroupInput && { + controlGroupInput: controlGroupInputIn(controlGroupInput), + }), + ...(options && { + optionsJSON: JSON.stringify(options), + }), + ...(panels && { + panelsJSON: panelsIn(panels), + }), + ...(kibanaSavedObjectMeta && { + kibanaSavedObjectMeta: kibanaSavedObjectMetaIn(kibanaSavedObjectMeta), + }), + }; + return { attributes: soAttributes, error: null }; + } catch (e) { + return { attributes: null, error: e }; + } +}; + +type PartialSavedObject = Omit>, 'references'> & { + references: SavedObjectReference[] | undefined; +}; + +export function savedObjectToItem( + savedObject: SavedObject, + partial: false, + allowedAttributes?: string[] +): SavedObjectToItemReturn; + +export function savedObjectToItem( + savedObject: PartialSavedObject, + partial: true, + allowedAttributes?: string[] +): SavedObjectToItemReturn; + +export function savedObjectToItem( + savedObject: + | SavedObject + | PartialSavedObject, + partial: boolean, + allowedAttributes?: string[] +): SavedObjectToItemReturn { + const { + id, + type, + updated_at: updatedAt, + updated_by: updatedBy, + created_at: createdAt, + created_by: createdBy, + attributes, + error, + namespaces, + references, + version, + managed, + } = savedObject; + + try { + const attributesOut = allowedAttributes + ? pick(dashboardAttributesOut(attributes), allowedAttributes) + : dashboardAttributesOut(attributes); + return { + item: { + id, + type, + updatedAt, + updatedBy, + createdAt, + createdBy, + attributes: attributesOut, + error, + namespaces, + references, + version, + managed, + }, + error: null, + }; + } catch (e) { + return { item: null, error: e }; + } +} diff --git a/src/plugins/dashboard/server/content_management/v3/types.ts b/src/plugins/dashboard/server/content_management/v3/types.ts new file mode 100644 index 000000000000..36f277ff3b26 --- /dev/null +++ b/src/plugins/dashboard/server/content_management/v3/types.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". + */ + +import { TypeOf } from '@kbn/config-schema'; +import { + CreateIn, + GetIn, + SearchIn, + SearchResult, + UpdateIn, +} from '@kbn/content-management-plugin/common'; +import { SavedObjectReference } from '@kbn/core-saved-objects-api-server'; +import { + dashboardItemSchema, + controlGroupInputSchema, + gridDataSchema, + panelSchema, + dashboardAttributesSchema, + dashboardCreateOptionsSchema, + dashboardCreateResultSchema, + dashboardGetResultSchema, + dashboardSearchOptionsSchema, + dashboardSearchResultsSchema, + dashboardUpdateOptionsSchema, + optionsSchema, +} from './cm_services'; +import { CONTENT_ID } from '../../../common/content_management'; +import { DashboardSavedObjectAttributes } from '../../dashboard_saved_object'; + +export type DashboardOptions = TypeOf; + +// Panel config has some defined types but also allows for custom keys added by embeddables +// The schema uses "unknowns: 'allow'" to permit any other keys, but the TypeOf helper does not +// recognize this, so we need to manually extend the type here. +export type DashboardPanel = Omit, 'panelConfig'> & { + panelConfig: TypeOf['panelConfig'] & { [key: string]: any }; +}; +export type DashboardAttributes = Omit, 'panels'> & { + panels: DashboardPanel[]; +}; + +export type DashboardItem = TypeOf; +export type PartialDashboardItem = Omit & { + attributes: Partial; + references: SavedObjectReference[] | undefined; +}; + +export type ControlGroupAttributes = TypeOf; +export type GridData = TypeOf; + +export type DashboardGetIn = GetIn; +export type DashboardGetOut = TypeOf; + +export type DashboardCreateIn = CreateIn; +export type DashboardCreateOut = TypeOf; +export type DashboardCreateOptions = TypeOf; + +export type DashboardUpdateIn = UpdateIn>; +export type DashboardUpdateOut = TypeOf; +export type DashboardUpdateOptions = TypeOf; + +export type DashboardSearchIn = SearchIn; +export type DashboardSearchOptions = TypeOf; +export type DashboardSearchOut = SearchResult>; + +export type SavedObjectToItemReturn = + | { + item: T; + error: null; + } + | { + item: null; + error: Error; + }; + +export type ItemAttrsToSavedObjectAttrsReturn = + | { + attributes: DashboardSavedObjectAttributes; + error: null; + } + | { + attributes: null; + error: Error; + }; diff --git a/src/plugins/dashboard/server/dashboard_saved_object/dashboard_saved_object.ts b/src/plugins/dashboard/server/dashboard_saved_object/dashboard_saved_object.ts index fc551d823377..3b7f137cc1d9 100644 --- a/src/plugins/dashboard/server/dashboard_saved_object/dashboard_saved_object.ts +++ b/src/plugins/dashboard/server/dashboard_saved_object/dashboard_saved_object.ts @@ -10,19 +10,21 @@ import { ANALYTICS_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server'; import { SavedObjectsType } from '@kbn/core/server'; -import { dashboardAttributesSchema as dashboardAttributesSchemaV1 } from '../content_management/schema/v1'; -import { dashboardAttributesSchema as dashboardAttributesSchemaV2 } from '../content_management/schema/v2'; +import { dashboardAttributesSchema as dashboardAttributesSchemaV1 } from './schema/v1'; +import { dashboardAttributesSchema as dashboardAttributesSchemaV2 } from './schema/v2'; import { createDashboardSavedObjectTypeMigrations, DashboardSavedObjectTypeMigrationsDeps, } from './migrations/dashboard_saved_object_migrations'; +export const DASHBOARD_SAVED_OBJECT_TYPE = 'dashboard'; + export const createDashboardSavedObjectType = ({ migrationDeps, }: { migrationDeps: DashboardSavedObjectTypeMigrationsDeps; }): SavedObjectsType => ({ - name: 'dashboard', + name: DASHBOARD_SAVED_OBJECT_TYPE, indexPattern: ANALYTICS_SAVED_OBJECT_INDEX, hidden: false, namespaceType: 'multiple-isolated', diff --git a/src/plugins/dashboard/server/dashboard_saved_object/index.ts b/src/plugins/dashboard/server/dashboard_saved_object/index.ts index 912c508f0ced..23c91f2c6ea3 100644 --- a/src/plugins/dashboard/server/dashboard_saved_object/index.ts +++ b/src/plugins/dashboard/server/dashboard_saved_object/index.ts @@ -7,4 +7,8 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export { createDashboardSavedObjectType } from './dashboard_saved_object'; +export { + createDashboardSavedObjectType, + DASHBOARD_SAVED_OBJECT_TYPE, +} from './dashboard_saved_object'; +export type { DashboardSavedObjectAttributes, GridData, SavedDashboardPanel } from './schema'; diff --git a/src/plugins/dashboard/server/dashboard_saved_object/migrations/dashboard_saved_object_migrations.test.ts b/src/plugins/dashboard/server/dashboard_saved_object/migrations/dashboard_saved_object_migrations.test.ts index 7abb1523e361..b5f5b6b20b31 100644 --- a/src/plugins/dashboard/server/dashboard_saved_object/migrations/dashboard_saved_object_migrations.test.ts +++ b/src/plugins/dashboard/server/dashboard_saved_object/migrations/dashboard_saved_object_migrations.test.ts @@ -613,12 +613,11 @@ describe('dashboard', () => { expect(newDoc).toMatchInlineSnapshot(` Object { "attributes": Object { - "description": "", "kibanaSavedObjectMeta": Object { "searchSourceJSON": "{\\"query\\":{\\"language\\":\\"kuery\\",\\"query\\":\\"\\"},\\"filter\\":[{\\"query\\":{\\"match_phrase\\":{\\"machine.os.keyword\\":\\"osx\\"}},\\"$state\\":{\\"store\\":\\"appState\\"},\\"meta\\":{\\"type\\":\\"phrase\\",\\"key\\":\\"machine.os.keyword\\",\\"params\\":{\\"query\\":\\"osx\\"},\\"disabled\\":false,\\"negate\\":false,\\"alias\\":null,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\\"}}]}", }, - "optionsJSON": "{\\"useMargins\\":true,\\"hidePanelTitles\\":false}", - "panelsJSON": "[{\\"version\\":\\"7.9.3\\",\\"type\\":\\"visualization\\",\\"gridData\\":{\\"x\\":0,\\"y\\":0,\\"w\\":24,\\"h\\":15,\\"i\\":\\"82fa0882-9f9e-476a-bbb9-03555e5ced91\\"},\\"panelIndex\\":\\"82fa0882-9f9e-476a-bbb9-03555e5ced91\\",\\"embeddableConfig\\":{\\"enhancements\\":{\\"dynamicActions\\":{\\"events\\":[]}}},\\"panelRefName\\":\\"panel_82fa0882-9f9e-476a-bbb9-03555e5ced91\\"}]", + "optionsJSON": "{\\"hidePanelTitles\\":false,\\"useMargins\\":true,\\"syncColors\\":true,\\"syncCursor\\":true,\\"syncTooltips\\":true}", + "panelsJSON": "[{\\"version\\":\\"7.9.3\\",\\"type\\":\\"visualization\\",\\"panelRefName\\":\\"panel_82fa0882-9f9e-476a-bbb9-03555e5ced91\\",\\"embeddableConfig\\":{\\"enhancements\\":{\\"dynamicActions\\":{\\"events\\":[]}}},\\"panelIndex\\":\\"82fa0882-9f9e-476a-bbb9-03555e5ced91\\",\\"gridData\\":{\\"x\\":0,\\"y\\":0,\\"w\\":24,\\"h\\":15,\\"i\\":\\"82fa0882-9f9e-476a-bbb9-03555e5ced91\\"}}]", "timeRestore": false, "title": "Dashboard A", "version": 1, @@ -710,7 +709,7 @@ describe('dashboard', () => { contextMock ); expect(migratedDoc.attributes.panelsJSON).toMatchInlineSnapshot( - `"[{\\"version\\":\\"7.9.3\\",\\"gridData\\":{\\"x\\":0,\\"y\\":0,\\"w\\":24,\\"h\\":15,\\"i\\":\\"0\\"},\\"panelIndex\\":\\"0\\",\\"embeddableConfig\\":{}},{\\"version\\":\\"7.13.0\\",\\"gridData\\":{\\"x\\":24,\\"y\\":0,\\"w\\":24,\\"h\\":15,\\"i\\":\\"1\\"},\\"panelIndex\\":\\"1\\",\\"embeddableConfig\\":{\\"attributes\\":{\\"byValueThing\\":\\"ThisIsByValue\\"},\\"superCoolKey\\":\\"ONLY 4 BY VALUE EMBEDDABLES THANK YOU VERY MUCH\\"}}]"` + `"[{\\"version\\":\\"7.9.3\\",\\"gridData\\":{\\"x\\":0,\\"y\\":0,\\"w\\":24,\\"h\\":15,\\"i\\":\\"0\\"},\\"panelIndex\\":\\"0\\",\\"embeddableConfig\\":{}},{\\"gridData\\":{\\"x\\":24,\\"y\\":0,\\"w\\":24,\\"h\\":15,\\"i\\":\\"1\\"},\\"panelIndex\\":\\"1\\",\\"embeddableConfig\\":{\\"attributes\\":{\\"byValueThing\\":\\"ThisIsByValue\\"},\\"superCoolKey\\":\\"ONLY 4 BY VALUE EMBEDDABLES THANK YOU VERY MUCH\\"},\\"version\\":\\"7.13.0\\"}]"` ); }); }); diff --git a/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_by_value_dashboard_panels.ts b/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_by_value_dashboard_panels.ts index 1b1d04cdebf7..0e32e2feec30 100644 --- a/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_by_value_dashboard_panels.ts +++ b/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_by_value_dashboard_panels.ts @@ -9,8 +9,8 @@ import { CONTROL_GROUP_TYPE } from '@kbn/controls-plugin/common'; import { - controlGroupSerializedStateToSerializableRuntimeState, - serializableRuntimeStateToControlGroupSerializedState, + controlGroupSavedObjectStateToSerializableRuntimeState, + serializableRuntimeStateToControlGroupSavedObjectState, } from '@kbn/controls-plugin/server'; import { Serializable, SerializableRecord } from '@kbn/utility-types'; import { SavedObjectMigrationFn } from '@kbn/core/server'; @@ -20,8 +20,8 @@ import { SavedObjectEmbeddableInput } from '@kbn/embeddable-plugin/common'; import { convertPanelStateToSavedDashboardPanel, convertSavedDashboardPanelToPanelState, -} from '../../../common'; -import { SavedDashboardPanel } from '../../../common/content_management'; +} from './utils'; +import type { SavedDashboardPanel } from '..'; type ValueOrReferenceInput = SavedObjectEmbeddableInput & { attributes?: Serializable; @@ -35,7 +35,7 @@ export const migrateByValueDashboardPanels = const { attributes } = doc; if (attributes?.controlGroupInput) { - const controlGroupState = controlGroupSerializedStateToSerializableRuntimeState( + const controlGroupState = controlGroupSavedObjectStateToSerializableRuntimeState( attributes.controlGroupInput ); const migratedControlGroupInput = migrate({ @@ -43,7 +43,7 @@ export const migrateByValueDashboardPanels = type: CONTROL_GROUP_TYPE, } as SerializableRecord); attributes.controlGroupInput = - serializableRuntimeStateToControlGroupSerializedState(migratedControlGroupInput); + serializableRuntimeStateToControlGroupSavedObjectState(migratedControlGroupInput); } // Skip if panelsJSON is missing otherwise this will cause saved object import to fail when diff --git a/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_extract_panel_references.ts b/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_extract_panel_references.ts index 1782a63beda5..091ef2132267 100644 --- a/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_extract_panel_references.ts +++ b/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_extract_panel_references.ts @@ -7,11 +7,12 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { SavedObjectMigrationFn } from '@kbn/core/server'; +import { SavedObject, SavedObjectMigrationFn } from '@kbn/core/server'; import { extractReferences, injectReferences } from '../../../common'; -import { DashboardAttributes } from '../../../common/content_management'; -import { DashboardSavedObjectTypeMigrationsDeps } from './dashboard_saved_object_migrations'; +import type { DashboardSavedObjectTypeMigrationsDeps } from './dashboard_saved_object_migrations'; +import type { DashboardSavedObjectAttributes } from '../schema'; +import { itemAttrsToSavedObjectAttrs, savedObjectToItem } from '../../content_management/latest'; /** * In 7.8.0 we introduced dashboard drilldowns which are stored inside dashboard saved object as part of embeddable state @@ -26,7 +27,7 @@ import { DashboardSavedObjectTypeMigrationsDeps } from './dashboard_saved_object */ export function createExtractPanelReferencesMigration( deps: DashboardSavedObjectTypeMigrationsDeps -): SavedObjectMigrationFn { +): SavedObjectMigrationFn { return (doc) => { const references = doc.references ?? []; @@ -36,19 +37,32 @@ export function createExtractPanelReferencesMigration( */ const oldNonPanelReferences = references.filter((ref) => !ref.name.startsWith('panel_')); + // Use Content Management to convert the saved object to the DashboardAttributes + // expected by injectReferences + const { item, error: itemError } = savedObjectToItem( + doc as unknown as SavedObject, + false + ); + + if (itemError) throw itemError; + + const parsedAttributes = item.attributes; const injectedAttributes = injectReferences( { - attributes: doc.attributes, + attributes: parsedAttributes, references, }, { embeddablePersistableStateService: deps.embeddable } ); - const { attributes, references: newPanelReferences } = extractReferences( + const { attributes: extractedAttributes, references: newPanelReferences } = extractReferences( { attributes: injectedAttributes, references: [] }, { embeddablePersistableStateService: deps.embeddable } ); + const { attributes, error: attributesError } = itemAttrsToSavedObjectAttrs(extractedAttributes); + if (attributesError) throw attributesError; + return { ...doc, references: [...oldNonPanelReferences, ...newPanelReferences], diff --git a/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_hidden_titles.ts b/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_hidden_titles.ts index c223ff0bc32a..77c114315ba1 100644 --- a/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_hidden_titles.ts +++ b/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_hidden_titles.ts @@ -7,14 +7,14 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { SavedObjectMigrationFn } from '@kbn/core/server'; -import { EmbeddableInput } from '@kbn/embeddable-plugin/common'; +import type { SavedObjectMigrationFn } from '@kbn/core/server'; +import type { EmbeddableInput } from '@kbn/embeddable-plugin/common'; +import type { SavedDashboardPanel } from '../schema'; import { convertSavedDashboardPanelToPanelState, convertPanelStateToSavedDashboardPanel, -} from '../../../common'; -import { SavedDashboardPanel } from '../../../common/content_management'; +} from './utils'; /** * Before 7.10, hidden panel titles were stored as a blank string on the title attribute. In 7.10, this was replaced diff --git a/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_to_730/migrate_to_730_panels.ts b/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_to_730/migrate_to_730_panels.ts index ab05f64a2d71..e23ccfd00153 100644 --- a/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_to_730/migrate_to_730_panels.ts +++ b/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_to_730/migrate_to_730_panels.ts @@ -13,7 +13,7 @@ import semverSatisfies from 'semver/functions/satisfies'; import { i18n } from '@kbn/i18n'; import type { SerializableRecord } from '@kbn/utility-types'; -import { +import type { SavedDashboardPanel620, SavedDashboardPanel630, SavedDashboardPanel610, @@ -25,7 +25,7 @@ import { RawSavedDashboardPanel640To720, RawSavedDashboardPanel730ToLatest, } from './types'; -import { GridData } from '../../../../common/content_management'; +import type { GridData } from '../../../content_management'; const PANEL_HEIGHT_SCALE_FACTOR = 5; const PANEL_HEIGHT_SCALE_FACTOR_WITH_MARGINS = 4; diff --git a/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_to_730/migrations_730.ts b/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_to_730/migrations_730.ts index 6af69882b077..6da3c1510530 100644 --- a/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_to_730/migrations_730.ts +++ b/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_to_730/migrations_730.ts @@ -49,7 +49,7 @@ export const migrations730 = (doc: DashboardDoc700To720, { log }: SavedObjectMig } try { - const searchSource = JSON.parse(doc.attributes.kibanaSavedObjectMeta.searchSourceJSON); + const searchSource = JSON.parse(doc.attributes.kibanaSavedObjectMeta.searchSourceJSON!); doc.attributes.kibanaSavedObjectMeta.searchSourceJSON = JSON.stringify( moveFiltersToQuery(searchSource) ); diff --git a/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_to_730/types.ts b/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_to_730/types.ts index 750fd736c966..585b9c55d501 100644 --- a/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_to_730/types.ts +++ b/src/plugins/dashboard/server/dashboard_saved_object/migrations/migrate_to_730/types.ts @@ -10,14 +10,12 @@ import type { Serializable } from '@kbn/utility-types'; import { SavedObjectReference } from '@kbn/core/server'; -import type { - GridData, - DashboardAttributes as CurrentDashboardAttributes, // Dashboard attributes from common are the source of truth for the current version. -} from '../../../../common/content_management'; +import type { GridData } from '../../../content_management'; +import type { DashboardSavedObjectAttributes } from '../../schema'; interface KibanaAttributes { kibanaSavedObjectMeta: { - searchSourceJSON: string; + searchSourceJSON?: string; }; } @@ -45,7 +43,7 @@ interface DashboardAttributesTo720 extends KibanaAttributes { optionsJSON?: string; } -export type DashboardDoc730ToLatest = Doc; +export type DashboardDoc730ToLatest = Doc; export type DashboardDoc700To720 = Doc; diff --git a/src/plugins/dashboard/common/lib/dashboard_panel_converters.test.ts b/src/plugins/dashboard/server/dashboard_saved_object/migrations/utils.test.ts similarity index 82% rename from src/plugins/dashboard/common/lib/dashboard_panel_converters.test.ts rename to src/plugins/dashboard/server/dashboard_saved_object/migrations/utils.test.ts index f750d95ca2ef..17aca8fef68c 100644 --- a/src/plugins/dashboard/common/lib/dashboard_panel_converters.test.ts +++ b/src/plugins/dashboard/server/dashboard_saved_object/migrations/utils.test.ts @@ -7,13 +7,14 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import type { EmbeddableInput } from '@kbn/embeddable-plugin/common/types'; +import type { SavedDashboardPanel } from '../schema'; +import type { DashboardPanelState } from '../../../common'; + import { convertSavedDashboardPanelToPanelState, convertPanelStateToSavedDashboardPanel, -} from './dashboard_panel_converters'; -import { SavedDashboardPanel } from '../content_management'; -import { DashboardPanelState } from '../dashboard_container/types'; -import { EmbeddableInput } from '@kbn/embeddable-plugin/common/types'; +} from './utils'; test('convertSavedDashboardPanelToPanelState', () => { const savedDashboardPanel: SavedDashboardPanel = { @@ -148,7 +149,7 @@ test('convertPanelStateToSavedDashboardPanel will not leave title as part of emb expect(converted.title).toBe('title'); }); -test('convertPanelStateToSavedDashboardPanel retains legacy version info when not passed removeLegacyVersion', () => { +test('convertPanelStateToSavedDashboardPanel retains legacy version info', () => { const dashboardPanel: DashboardPanelState = { gridData: { x: 0, @@ -168,24 +169,3 @@ test('convertPanelStateToSavedDashboardPanel retains legacy version info when no const converted = convertPanelStateToSavedDashboardPanel(dashboardPanel); expect(converted.version).toBe('8.10.0'); }); - -test('convertPanelStateToSavedDashboardPanel removes legacy version info when passed removeLegacyVersion', () => { - const dashboardPanel: DashboardPanelState = { - gridData: { - x: 0, - y: 0, - h: 15, - w: 15, - i: '123', - }, - explicitInput: { - id: '123', - title: 'title', - } as EmbeddableInput, - type: 'search', - version: '8.10.0', - }; - - const converted = convertPanelStateToSavedDashboardPanel(dashboardPanel, true); - expect(converted.version).not.toBeDefined(); -}); diff --git a/src/plugins/dashboard/server/dashboard_saved_object/migrations/utils.ts b/src/plugins/dashboard/server/dashboard_saved_object/migrations/utils.ts new file mode 100644 index 000000000000..4ed8ec5b8e97 --- /dev/null +++ b/src/plugins/dashboard/server/dashboard_saved_object/migrations/utils.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 { omit } from 'lodash'; +import type { EmbeddableInput, SavedObjectEmbeddableInput } from '@kbn/embeddable-plugin/common'; +import type { SavedDashboardPanel } from '../schema'; +import type { DashboardPanelState } from '../../../common'; + +export function convertSavedDashboardPanelToPanelState< + TEmbeddableInput extends EmbeddableInput | SavedObjectEmbeddableInput = SavedObjectEmbeddableInput +>(savedDashboardPanel: SavedDashboardPanel): DashboardPanelState { + return { + type: savedDashboardPanel.type, + gridData: savedDashboardPanel.gridData, + panelRefName: savedDashboardPanel.panelRefName, + explicitInput: { + id: savedDashboardPanel.panelIndex, + ...(savedDashboardPanel.id !== undefined && { savedObjectId: savedDashboardPanel.id }), + ...(savedDashboardPanel.title !== undefined && { title: savedDashboardPanel.title }), + ...savedDashboardPanel.embeddableConfig, + } as TEmbeddableInput, + version: savedDashboardPanel.version, + }; +} + +export function convertPanelStateToSavedDashboardPanel( + panelState: DashboardPanelState +): SavedDashboardPanel { + const savedObjectId = (panelState.explicitInput as SavedObjectEmbeddableInput).savedObjectId; + const panelIndex = panelState.explicitInput.id; + return { + type: panelState.type, + gridData: { + ...panelState.gridData, + i: panelIndex, + }, + panelIndex, + embeddableConfig: omit(panelState.explicitInput, ['id', 'savedObjectId', 'title']), + ...(panelState.explicitInput.title !== undefined && { title: panelState.explicitInput.title }), + ...(savedObjectId !== undefined && { id: savedObjectId }), + ...(panelState.panelRefName !== undefined && { panelRefName: panelState.panelRefName }), + ...(panelState.version !== undefined && { version: panelState.version }), + }; +} diff --git a/src/plugins/dashboard/server/dashboard_saved_object/schema/index.ts b/src/plugins/dashboard/server/dashboard_saved_object/schema/index.ts new file mode 100644 index 000000000000..4c50de472f53 --- /dev/null +++ b/src/plugins/dashboard/server/dashboard_saved_object/schema/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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". + */ + +export type { DashboardSavedObjectAttributes, GridData, SavedDashboardPanel } from './latest'; +export { dashboardSavedObjectSchema } from './latest'; diff --git a/src/plugins/dashboard/server/dashboard_saved_object/schema/latest.ts b/src/plugins/dashboard/server/dashboard_saved_object/schema/latest.ts new file mode 100644 index 000000000000..a40e476abe79 --- /dev/null +++ b/src/plugins/dashboard/server/dashboard_saved_object/schema/latest.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", 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". + */ + +// Latest model version for dashboard saved objects is v2 +export { + dashboardAttributesSchema as dashboardSavedObjectSchema, + type DashboardAttributes as DashboardSavedObjectAttributes, + type GridData, + type SavedDashboardPanel, +} from './v2'; diff --git a/src/plugins/dashboard/server/dashboard_saved_object/schema/v1/index.ts b/src/plugins/dashboard/server/dashboard_saved_object/schema/v1/index.ts new file mode 100644 index 000000000000..e52a6ca4075a --- /dev/null +++ b/src/plugins/dashboard/server/dashboard_saved_object/schema/v1/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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". + */ + +export type { DashboardAttributes } from './types'; +export { controlGroupInputSchema, dashboardAttributesSchema } from './v1'; diff --git a/src/plugins/dashboard/server/dashboard_saved_object/schema/v1/types.ts b/src/plugins/dashboard/server/dashboard_saved_object/schema/v1/types.ts new file mode 100644 index 000000000000..8717851845cf --- /dev/null +++ b/src/plugins/dashboard/server/dashboard_saved_object/schema/v1/types.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 { TypeOf } from '@kbn/config-schema'; +import { dashboardAttributesSchema } from './v1'; + +export type DashboardAttributes = TypeOf; diff --git a/src/plugins/dashboard/server/dashboard_saved_object/schema/v1/v1.ts b/src/plugins/dashboard/server/dashboard_saved_object/schema/v1/v1.ts new file mode 100644 index 000000000000..63b4cd3c2c10 --- /dev/null +++ b/src/plugins/dashboard/server/dashboard_saved_object/schema/v1/v1.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 { schema } from '@kbn/config-schema'; + +export const controlGroupInputSchema = schema + .object({ + panelsJSON: schema.maybe(schema.string()), + controlStyle: schema.maybe(schema.string()), + chainingSystem: schema.maybe(schema.string()), + ignoreParentSettingsJSON: schema.maybe(schema.string()), + }) + .extends({}, { unknowns: 'ignore' }); + +export const dashboardAttributesSchema = schema.object( + { + // General + title: schema.string(), + description: schema.string({ defaultValue: '' }), + + // Search + kibanaSavedObjectMeta: schema.object({ + searchSourceJSON: schema.maybe(schema.string()), + }), + + // Time + timeRestore: schema.maybe(schema.boolean()), + timeFrom: schema.maybe(schema.string()), + timeTo: schema.maybe(schema.string()), + refreshInterval: schema.maybe( + schema.object({ + pause: schema.boolean(), + value: schema.number(), + display: schema.maybe(schema.string()), + section: schema.maybe(schema.number()), + }) + ), + + // Dashboard Content + controlGroupInput: schema.maybe(controlGroupInputSchema), + panelsJSON: schema.string({ defaultValue: '[]' }), + optionsJSON: schema.maybe(schema.string()), + + // Legacy + hits: schema.maybe(schema.number()), + version: schema.maybe(schema.number()), + }, + { unknowns: 'forbid' } +); diff --git a/src/plugins/dashboard/server/dashboard_saved_object/schema/v2/index.ts b/src/plugins/dashboard/server/dashboard_saved_object/schema/v2/index.ts new file mode 100644 index 000000000000..2fda02230ed6 --- /dev/null +++ b/src/plugins/dashboard/server/dashboard_saved_object/schema/v2/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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". + */ + +export type { DashboardAttributes, GridData, SavedDashboardPanel } from './types'; +export { controlGroupInputSchema, dashboardAttributesSchema } from './v2'; diff --git a/src/plugins/dashboard/server/dashboard_saved_object/schema/v2/types.ts b/src/plugins/dashboard/server/dashboard_saved_object/schema/v2/types.ts new file mode 100644 index 000000000000..e50a27efe2b3 --- /dev/null +++ b/src/plugins/dashboard/server/dashboard_saved_object/schema/v2/types.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", 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 { Serializable } from '@kbn/utility-types'; +import { TypeOf } from '@kbn/config-schema'; +import { dashboardAttributesSchema, gridDataSchema } from './v2'; + +export type DashboardAttributes = TypeOf; +export type GridData = TypeOf; + +/** + * A saved dashboard panel parsed directly from the Dashboard Attributes panels JSON + */ +export interface SavedDashboardPanel { + embeddableConfig: { [key: string]: Serializable }; // parsed into the panel's explicitInput + id?: string; // the saved object id for by reference panels + type: string; // the embeddable type + panelRefName?: string; + gridData: GridData; + panelIndex: string; + title?: string; + + /** + * This version key was used to store Kibana version information from versions 7.3.0 -> 8.11.0. + * As of version 8.11.0, the versioning information is now per-embeddable-type and is stored on the + * embeddable's input. (embeddableConfig in this type). + */ + version?: string; +} diff --git a/src/plugins/dashboard/server/dashboard_saved_object/schema/v2/v2.ts b/src/plugins/dashboard/server/dashboard_saved_object/schema/v2/v2.ts new file mode 100644 index 000000000000..dc0ed3eb84cb --- /dev/null +++ b/src/plugins/dashboard/server/dashboard_saved_object/schema/v2/v2.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 { schema } from '@kbn/config-schema'; +import { + controlGroupInputSchema as controlGroupInputSchemaV1, + dashboardAttributesSchema as dashboardAttributesSchemaV1, +} from '../v1'; + +export const controlGroupInputSchema = controlGroupInputSchemaV1.extends( + { + showApplySelections: schema.maybe(schema.boolean()), + }, + { unknowns: 'ignore' } +); + +export const dashboardAttributesSchema = dashboardAttributesSchemaV1.extends( + { + controlGroupInput: schema.maybe(controlGroupInputSchema), + }, + { unknowns: 'ignore' } +); + +export const gridDataSchema = schema.object({ + x: schema.number(), + y: schema.number(), + w: schema.number(), + h: schema.number(), + i: schema.string(), +}); diff --git a/src/plugins/dashboard/server/index.ts b/src/plugins/dashboard/server/index.ts index f76a75cb837b..94e7ed14378c 100644 --- a/src/plugins/dashboard/server/index.ts +++ b/src/plugins/dashboard/server/index.ts @@ -26,3 +26,7 @@ export async function plugin(initializerContext: PluginInitializerContext) { } export type { DashboardPluginSetup, DashboardPluginStart } from './types'; +export type { DashboardAttributes } from './content_management'; +export type { DashboardSavedObjectAttributes } from './dashboard_saved_object'; + +export { PUBLIC_API_PATH } from './api/constants'; diff --git a/src/plugins/dashboard/server/plugin.ts b/src/plugins/dashboard/server/plugin.ts index 3218ee85ef38..e3d67ca10716 100644 --- a/src/plugins/dashboard/server/plugin.ts +++ b/src/plugins/dashboard/server/plugin.ts @@ -30,6 +30,7 @@ import { createDashboardSavedObjectType } from './dashboard_saved_object'; import { CONTENT_ID, LATEST_VERSION } from '../common/content_management'; import { registerDashboardUsageCollector } from './usage/register_collector'; import { dashboardPersistableStateServiceFactory } from './dashboard_container/dashboard_container_embeddable_factory'; +import { registerAPIRoutes } from './api'; interface SetupDeps { embeddable: EmbeddableSetup; @@ -111,6 +112,12 @@ export class DashboardPlugin core.uiSettings.register(getUISettings()); + registerAPIRoutes({ + http: core.http, + contentManagement: plugins.contentManagement, + logger: this.logger, + }); + return {}; } diff --git a/src/plugins/dashboard/server/usage/dashboard_telemetry.test.ts b/src/plugins/dashboard/server/usage/dashboard_telemetry.test.ts index 225ac7743d23..8f4f94d3621e 100644 --- a/src/plugins/dashboard/server/usage/dashboard_telemetry.test.ts +++ b/src/plugins/dashboard/server/usage/dashboard_telemetry.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { SavedDashboardPanel } from '../../common/content_management'; +import { SavedDashboardPanel } from '../dashboard_saved_object'; import { getEmptyDashboardData, collectPanelsByType } from './dashboard_telemetry'; import { EmbeddableStateWithType } from '@kbn/embeddable-plugin/common'; import { createEmbeddablePersistableStateServiceMock } from '@kbn/embeddable-plugin/common/mocks'; diff --git a/src/plugins/dashboard/server/usage/dashboard_telemetry.ts b/src/plugins/dashboard/server/usage/dashboard_telemetry.ts index 0048e081e6f6..f26de753c12e 100644 --- a/src/plugins/dashboard/server/usage/dashboard_telemetry.ts +++ b/src/plugins/dashboard/server/usage/dashboard_telemetry.ts @@ -17,7 +17,7 @@ import { import { EmbeddablePersistableStateService } from '@kbn/embeddable-plugin/common'; import { TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; -import { DashboardAttributes, SavedDashboardPanel } from '../../common/content_management'; +import { DashboardSavedObjectAttributes, SavedDashboardPanel } from '../dashboard_saved_object'; import { TASK_ID } from './dashboard_telemetry_collection_task'; import { emptyState, type LatestTaskStateSchema } from './task_state'; @@ -95,7 +95,7 @@ export const collectPanelsByType = ( export const controlsCollectorFactory = (embeddableService: EmbeddablePersistableStateService) => - (attributes: DashboardAttributes, collectorData: DashboardCollectorData) => { + (attributes: DashboardSavedObjectAttributes, collectorData: DashboardCollectorData) => { if (!isEmpty(attributes.controlGroupInput)) { collectorData.controls = embeddableService.telemetry( { diff --git a/src/plugins/dashboard/server/usage/dashboard_telemetry_collection_task.ts b/src/plugins/dashboard/server/usage/dashboard_telemetry_collection_task.ts index d660af962db5..7eb4cebc39e4 100644 --- a/src/plugins/dashboard/server/usage/dashboard_telemetry_collection_task.ts +++ b/src/plugins/dashboard/server/usage/dashboard_telemetry_collection_task.ts @@ -23,9 +23,15 @@ import { collectPanelsByType, getEmptyDashboardData, } from './dashboard_telemetry'; -import { injectReferences } from '../../common'; -import { DashboardAttributesAndReferences } from '../../common/types'; -import { DashboardAttributes, SavedDashboardPanel } from '../../common/content_management'; +import type { + DashboardSavedObjectAttributes, + SavedDashboardPanel, +} from '../dashboard_saved_object'; + +interface DashboardSavedObjectAttributesAndReferences { + attributes: DashboardSavedObjectAttributes; + references: SavedObjectReference[]; +} // This task is responsible for running daily and aggregating all the Dashboard telemerty data // into a single document. This is an effort to make sure the load of fetching/parsing all of the @@ -88,17 +94,18 @@ export function dashboardTaskRunner(logger: Logger, core: CoreSetup, embeddable: async run() { let dashboardData = getEmptyDashboardData(); const controlsCollector = controlsCollectorFactory(embeddable); - const processDashboards = (dashboards: DashboardAttributesAndReferences[]) => { + const processDashboards = (dashboards: DashboardSavedObjectAttributesAndReferences[]) => { for (const dashboard of dashboards) { - const attributes = injectReferences(dashboard, { - embeddablePersistableStateService: embeddable, - }); + // TODO is this injecting references really necessary? + // const attributes = injectReferences(dashboard, { + // embeddablePersistableStateService: embeddable, + // }); - dashboardData = controlsCollector(attributes, dashboardData); + dashboardData = controlsCollector(dashboard.attributes, dashboardData); try { const panels = JSON.parse( - attributes.panelsJSON as string + dashboard.attributes.panelsJSON as string ) as unknown as SavedDashboardPanel[]; collectPanelsByType(panels, dashboardData, embeddable); @@ -129,7 +136,7 @@ export function dashboardTaskRunner(logger: Logger, core: CoreSetup, embeddable: const esClient = await getEsClient(); let result = await esClient.search<{ - dashboard: DashboardAttributes; + dashboard: DashboardSavedObjectAttributes; references: SavedObjectReference[]; }>(searchParams); @@ -144,8 +151,8 @@ export function dashboardTaskRunner(logger: Logger, core: CoreSetup, embeddable: } return undefined; }) - .filter( - (s): s is DashboardAttributesAndReferences => s !== undefined + .filter( + (s): s is DashboardSavedObjectAttributesAndReferences => s !== undefined ) ); @@ -163,8 +170,8 @@ export function dashboardTaskRunner(logger: Logger, core: CoreSetup, embeddable: } return undefined; }) - .filter( - (s): s is DashboardAttributesAndReferences => s !== undefined + .filter( + (s): s is DashboardSavedObjectAttributesAndReferences => s !== undefined ) ); } diff --git a/src/plugins/data/common/search/strategies/es_search/index.ts b/src/plugins/data/common/search/strategies/es_search/index.ts index 34d385a3f5d6..978132b3130d 100644 --- a/src/plugins/data/common/search/strategies/es_search/index.ts +++ b/src/plugins/data/common/search/strategies/es_search/index.ts @@ -8,3 +8,4 @@ */ export * from './types'; +export * from './response_utils'; diff --git a/src/plugins/data/server/search/strategies/es_search/response_utils.test.ts b/src/plugins/data/common/search/strategies/es_search/response_utils.test.ts similarity index 77% rename from src/plugins/data/server/search/strategies/es_search/response_utils.test.ts rename to src/plugins/data/common/search/strategies/es_search/response_utils.test.ts index add9653bf6a1..8c9fb108f23e 100644 --- a/src/plugins/data/server/search/strategies/es_search/response_utils.test.ts +++ b/src/plugins/data/common/search/strategies/es_search/response_utils.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getTotalLoaded, toKibanaSearchResponse, shimHitsTotal } from './response_utils'; +import { getTotalLoaded, shimHitsTotal } from './response_utils'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; describe('response utils', () => { @@ -29,34 +29,6 @@ describe('response utils', () => { }); }); - describe('toKibanaSearchResponse', () => { - it('returns rawResponse, isPartial, isRunning, total, and loaded', () => { - const result = toKibanaSearchResponse({ - _shards: { - successful: 10, - failed: 5, - skipped: 5, - total: 100, - }, - } as unknown as estypes.SearchResponse); - - expect(result).toEqual({ - rawResponse: { - _shards: { - successful: 10, - failed: 5, - skipped: 5, - total: 100, - }, - }, - isRunning: false, - isPartial: false, - total: 100, - loaded: 15, - }); - }); - }); - describe('shimHitsTotal', () => { test('returns the total if it is already numeric', () => { const result = shimHitsTotal({ diff --git a/src/plugins/data/server/search/strategies/es_search/response_utils.ts b/src/plugins/data/common/search/strategies/es_search/response_utils.ts similarity index 72% rename from src/plugins/data/server/search/strategies/es_search/response_utils.ts rename to src/plugins/data/common/search/strategies/es_search/response_utils.ts index 09683dd22b45..04d1a5d11cbe 100644 --- a/src/plugins/data/server/search/strategies/es_search/response_utils.ts +++ b/src/plugins/data/common/search/strategies/es_search/response_utils.ts @@ -7,10 +7,8 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { ConnectionRequestParams } from '@elastic/transport'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ISearchOptions } from '@kbn/search-types'; -import { sanitizeRequestParams } from '../../sanitize_request_params'; /** * Get the `total`/`loaded` for this response (see `IKibanaSearchResponse`). Note that `skipped` is @@ -23,23 +21,6 @@ export function getTotalLoaded(response: estypes.SearchResponse) { return { total, loaded }; } -/** - * Get the Kibana representation of this response (see `IKibanaSearchResponse`). - * @internal - */ -export function toKibanaSearchResponse( - rawResponse: estypes.SearchResponse, - requestParams?: ConnectionRequestParams -) { - return { - rawResponse, - isPartial: false, - isRunning: false, - ...(requestParams ? { requestParams: sanitizeRequestParams(requestParams) } : {}), - ...getTotalLoaded(rawResponse), - }; -} - /** * Temporary workaround until https://github.com/elastic/kibana/issues/26356 is addressed. * Since we are setting `track_total_hits` in the request, `hits.total` will be an object diff --git a/src/plugins/data/common/search/utils.ts b/src/plugins/data/common/search/utils.ts index 33c6b34ec363..baf3fe79b1ac 100644 --- a/src/plugins/data/common/search/utils.ts +++ b/src/plugins/data/common/search/utils.ts @@ -17,8 +17,10 @@ import { AggTypesDependencies } from '..'; /** * @returns true if response is abort */ -export const isAbortResponse = (response?: IKibanaSearchResponse) => { - return !response || !response.rawResponse; +export const isAbortResponse = ( + response?: IKibanaSearchResponse | { response: IKibanaSearchResponse } +) => { + return !response || !('rawResponse' in response || 'response' in response); }; /** diff --git a/src/plugins/data/public/search/search_interceptor/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor/search_interceptor.ts index 174dc35697eb..458171e64a1d 100644 --- a/src/plugins/data/public/search/search_interceptor/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor/search_interceptor.ts @@ -60,11 +60,19 @@ import type { } from '@kbn/search-types'; import { createEsError, isEsError, renderSearchError } from '@kbn/search-errors'; import type { IKibanaSearchResponse, ISearchOptions } from '@kbn/search-types'; +import { + AsyncSearchGetResponse, + ErrorResponseBase, + SqlGetAsyncResponse, +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ENHANCED_ES_SEARCH_STRATEGY, + ESQL_ASYNC_SEARCH_STRATEGY, + getTotalLoaded, IAsyncSearchOptions, isRunningResponse, pollSearch, + shimHitsTotal, UI_SETTINGS, } from '../../../common'; import { SearchUsageCollector } from '../collectors'; @@ -445,14 +453,75 @@ export class SearchInterceptor { if (this.bFetchDisabled) { const { executionContext, strategy, ...searchOptions } = this.getSerializableOptions(options); return this.deps.http - .post(`/internal/search/${strategy}${request.id ? `/${request.id}` : ''}`, { - version: '1', - signal: abortSignal, - context: executionContext, - body: JSON.stringify({ - ...request, - ...searchOptions, - }), + .post( + `/internal/search/${strategy}${request.id ? `/${request.id}` : ''}`, + { + version: '1', + signal: abortSignal, + context: executionContext, + body: JSON.stringify({ + ...request, + ...searchOptions, + stream: + strategy === ESQL_ASYNC_SEARCH_STRATEGY || + strategy === ENHANCED_ES_SEARCH_STRATEGY || + strategy === undefined, // undefined strategy is treated as enhanced ES + }), + asResponse: true, + } + ) + .then((rawResponse) => { + const warning = rawResponse.response?.headers.get('warning'); + const requestParams = + rawResponse.body && 'requestParams' in rawResponse.body + ? rawResponse.body.requestParams + : JSON.parse(rawResponse.response?.headers.get('kbn-search-request-params') || '{}'); + const isRestored = + rawResponse.body && 'isRestored' in rawResponse.body + ? rawResponse.body.isRestored + : rawResponse.response?.headers.get('kbn-search-is-restored') === '?1'; + + if (rawResponse.body && 'error' in rawResponse.body) { + // eslint-disable-next-line no-throw-literal + throw { + attributes: { + error: rawResponse.body.error, + rawResponse: rawResponse.body, + requestParams, + isRestored, + }, + }; + } + + switch (strategy) { + case ENHANCED_ES_SEARCH_STRATEGY: + if (rawResponse.body?.rawResponse) return rawResponse.body; + const typedResponse = rawResponse.body as unknown as AsyncSearchGetResponse; + const shimmedResponse = shimHitsTotal(typedResponse.response, { + legacyHitsTotal: searchOptions.legacyHitsTotal, + }); + return { + id: typedResponse.id, + isPartial: typedResponse.is_partial, + isRunning: typedResponse.is_running, + rawResponse: shimmedResponse, + warning, + requestParams, + isRestored, + ...getTotalLoaded(shimmedResponse), + }; + case ESQL_ASYNC_SEARCH_STRATEGY: + const esqlResponse = rawResponse.body as unknown as SqlGetAsyncResponse; + return { + id: esqlResponse.id, + rawResponse: esqlResponse, + isPartial: esqlResponse.is_partial, + isRunning: esqlResponse.is_running, + warning, + }; + default: + return rawResponse.body; + } }) .catch((e: IHttpFetchError) => { if (e?.body) { diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index ea54bfb9f70c..b4fe8438a46b 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -68,12 +68,13 @@ export type { AsyncSearchStatusResponse, } from './search'; export { - shimHitsTotal, SearchSessionService, NoSearchIdInSessionError, INITIAL_SEARCH_SESSION_REST_VERSION, } from './search'; +export { shimHitsTotal } from '../common/search'; + // Search namespace export const search = { aggs: { diff --git a/src/plugins/data/server/search/routes/search.ts b/src/plugins/data/server/search/routes/search.ts index 3f92583236ef..24ece630e736 100644 --- a/src/plugins/data/server/search/routes/search.ts +++ b/src/plugins/data/server/search/routes/search.ts @@ -10,6 +10,7 @@ import { first } from 'rxjs'; import { schema } from '@kbn/config-schema'; import { reportServerError } from '@kbn/kibana-utils-plugin/server'; +import { IncomingMessage } from 'http'; import { reportSearchError } from '../report_search_error'; import { getRequestAbortedSignal } from '../../lib'; import type { DataPluginRouter } from '../types'; @@ -25,6 +26,12 @@ export function registerSearchRoute(router: DataPluginRouter): void { .addVersion( { version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { request: { params: schema.object({ @@ -38,6 +45,7 @@ export function registerSearchRoute(router: DataPluginRouter): void { isStored: schema.maybe(schema.boolean()), isRestore: schema.maybe(schema.boolean()), retrieveResults: schema.maybe(schema.boolean()), + stream: schema.maybe(schema.boolean()), }, { unknowns: 'allow' } ), @@ -51,6 +59,7 @@ export function registerSearchRoute(router: DataPluginRouter): void { isStored, isRestore, retrieveResults, + stream, ...searchRequest } = request.body; const { strategy, id } = request.params; @@ -69,12 +78,23 @@ export function registerSearchRoute(router: DataPluginRouter): void { isStored, isRestore, retrieveResults, + stream, } ) .pipe(first()) .toPromise(); - return res.ok({ body: response }); + if (response && (response.rawResponse as unknown as IncomingMessage).pipe) { + return res.ok({ + body: response.rawResponse, + headers: { + 'kbn-search-is-restored': response.isRestored ? '?1' : '?0', + 'kbn-search-request-params': JSON.stringify(response.requestParams), + }, + }); + } else { + return res.ok({ body: response }); + } } catch (err) { return reportSearchError(res, err); } @@ -89,6 +109,12 @@ export function registerSearchRoute(router: DataPluginRouter): void { .addVersion( { version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { request: { params: schema.object({ diff --git a/src/plugins/data/server/search/strategies/es_search/es_search_strategy.test.ts b/src/plugins/data/server/search/strategies/es_search/es_search_strategy.test.ts index 65ea7f601672..c771cc08b5a5 100644 --- a/src/plugins/data/server/search/strategies/es_search/es_search_strategy.test.ts +++ b/src/plugins/data/server/search/strategies/es_search/es_search_strategy.test.ts @@ -10,7 +10,7 @@ import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { pluginInitializerContextConfigMock } from '@kbn/core/server/mocks'; -import { esSearchStrategyProvider } from './es_search_strategy'; +import { esSearchStrategyProvider, toKibanaSearchResponse } from './es_search_strategy'; import { SearchStrategyDependencies } from '../../types'; import indexNotFoundException from '../../../../common/search/test_data/index_not_found_exception.json'; @@ -211,3 +211,31 @@ describe('ES search strategy', () => { } }); }); + +describe('toKibanaSearchResponse', () => { + it('returns rawResponse, isPartial, isRunning, total, and loaded', () => { + const result = toKibanaSearchResponse({ + _shards: { + successful: 10, + failed: 5, + skipped: 5, + total: 100, + }, + } as unknown as estypes.SearchResponse); + + expect(result).toEqual({ + rawResponse: { + _shards: { + successful: 10, + failed: 5, + skipped: 5, + total: 100, + }, + }, + isRunning: false, + isPartial: false, + total: 100, + loaded: 15, + }); + }); +}); diff --git a/src/plugins/data/server/search/strategies/es_search/es_search_strategy.ts b/src/plugins/data/server/search/strategies/es_search/es_search_strategy.ts index 9955dec39866..39e2b6616239 100644 --- a/src/plugins/data/server/search/strategies/es_search/es_search_strategy.ts +++ b/src/plugins/data/server/search/strategies/es_search/es_search_strategy.ts @@ -8,15 +8,35 @@ */ import { firstValueFrom, from, Observable } from 'rxjs'; +import type { ConnectionRequestParams } from '@elastic/transport'; import { tap } from 'rxjs'; import type { Logger, SharedGlobalConfig } from '@kbn/core/server'; +import { estypes } from '@elastic/elasticsearch'; +import { shimHitsTotal, getTotalLoaded } from '../../../../common'; +import { sanitizeRequestParams } from '../../sanitize_request_params'; import { getKbnSearchError, KbnSearchError } from '../../report_search_error'; import type { ISearchStrategy } from '../../types'; import type { SearchUsage } from '../../collectors/search'; import { getDefaultSearchParams, getShardTimeout } from './request_utils'; -import { shimHitsTotal, toKibanaSearchResponse } from './response_utils'; import { searchUsageObserver } from '../../collectors/search/usage'; +/** + * Get the Kibana representation of this response (see `IKibanaSearchResponse`). + * @internal + */ +export function toKibanaSearchResponse( + rawResponse: estypes.SearchResponse, + requestParams?: ConnectionRequestParams +) { + return { + rawResponse, + isPartial: false, + isRunning: false, + ...(requestParams ? { requestParams: sanitizeRequestParams(requestParams) } : {}), + ...getTotalLoaded(rawResponse), + }; +} + export const esSearchStrategyProvider = ( config$: Observable, logger: Logger, diff --git a/src/plugins/data/server/search/strategies/es_search/index.ts b/src/plugins/data/server/search/strategies/es_search/index.ts index 5d2104e47e1c..2bd2a0f72d13 100644 --- a/src/plugins/data/server/search/strategies/es_search/index.ts +++ b/src/plugins/data/server/search/strategies/es_search/index.ts @@ -9,5 +9,4 @@ export { esSearchStrategyProvider } from './es_search_strategy'; export * from './request_utils'; -export * from './response_utils'; export { ES_SEARCH_STRATEGY } from '../../../../common'; diff --git a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.test.ts b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.test.ts index 2274cdf95230..a778ebbc8967 100644 --- a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.test.ts +++ b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.test.ts @@ -33,6 +33,11 @@ const mockAsyncStatusResponse = (isComplete = false) => ({ failed: 0, }, }, + headers: { + 'x-elasticsearch-async-id': + 'FlVYVkw0clJIUS1TMHpHdXA3a29pZUEedldKX1c1bnBRVXFmalZ4emV1cjFCUToxNjYzMDgx', + 'x-elasticsearch-async-is-running': isComplete ? '?0' : '?1', + }, }); const mockAsyncResponse = { @@ -47,6 +52,10 @@ const mockAsyncResponse = { }, }, }, + headers: { + 'x-elasticsearch-async-id': 'foo', + 'x-elasticsearch-async-is-running': '?0', + }, }; const mockRollupResponse = { @@ -335,6 +344,10 @@ describe('ES search strategy', () => { ...mockAsyncResponse.body, is_running: true, }, + headers: { + ...mockAsyncResponse.headers, + 'x-elasticsearch-async-is-running': '?1', + }, }); const params = { index: 'logstash-*', body: { query: {} } }; @@ -367,6 +380,10 @@ describe('ES search strategy', () => { ...mockAsyncResponse.body, is_running: true, }, + headers: { + ...mockAsyncResponse.headers, + 'x-elasticsearch-async-is-running': '?1', + }, }); const errResponse = new errors.ResponseError({ @@ -518,6 +535,10 @@ describe('ES search strategy', () => { ...mockAsyncResponse.body, is_running: true, }, + headers: { + ...mockAsyncResponse.headers, + 'x-elasticsearch-async-is-running': '?1', + }, }); const params = { index: 'logstash-*', body: { query: {} } }; diff --git a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts index 7e746b3adf57..dbaf97d03a63 100644 --- a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts +++ b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.ts @@ -26,12 +26,8 @@ import { } from './request_utils'; import { toAsyncKibanaSearchResponse, toAsyncKibanaSearchStatusResponse } from './response_utils'; import { SearchUsage, searchUsageObserver } from '../../collectors/search'; -import { - getDefaultSearchParams, - getShardTimeout, - getTotalLoaded, - shimHitsTotal, -} from '../es_search'; +import { getDefaultSearchParams, getShardTimeout } from '../es_search'; +import { getTotalLoaded, shimHitsTotal } from '../../../../common/search/strategies/es_search'; import { SearchConfigSchema } from '../../../config'; import { sanitizeRequestParams } from '../../sanitize_request_params'; @@ -85,12 +81,17 @@ export const enhancedEsSearchStrategyProvider = ( ? { wait_for_completion_timeout: request.params.wait_for_completion_timeout } : {}), }; - const { body, headers } = await client.asyncSearch.get( + const { body, headers, meta } = await client.asyncSearch.get( { ...params, id: id! }, - { ...options.transport, signal: options.abortSignal, meta: true } + { + ...options.transport, + signal: options.abortSignal, + meta: true, + asStream: options.stream, + } ); - const response = shimHitsTotal(body.response, options); - return toAsyncKibanaSearchResponse({ ...body, response }, headers?.warning); + + return toAsyncKibanaSearchResponse(body, headers, meta?.request?.params, options); } async function submitAsyncSearch( @@ -107,13 +108,10 @@ export const enhancedEsSearchStrategyProvider = ( ...options.transport, signal: options.abortSignal, meta: true, + asStream: options.stream, }); - const response = shimHitsTotal(body.response, options); - return toAsyncKibanaSearchResponse( - { ...body, response }, - headers?.warning, - meta?.request?.params - ); + + return toAsyncKibanaSearchResponse(body, headers, meta?.request?.params, options); } function asyncSearch( diff --git a/src/plugins/data/server/search/strategies/ese_search/response_utils.ts b/src/plugins/data/server/search/strategies/ese_search/response_utils.ts index af9a122d5747..cb8470a90e41 100644 --- a/src/plugins/data/server/search/strategies/ese_search/response_utils.ts +++ b/src/plugins/data/server/search/strategies/ese_search/response_utils.ts @@ -9,10 +9,11 @@ import type { ConnectionRequestParams } from '@elastic/transport'; import type { IKibanaSearchResponse } from '@kbn/search-types'; +import { IncomingHttpHeaders } from 'http'; import type { AsyncSearchResponse } from './types'; -import { getTotalLoaded } from '../es_search'; import { sanitizeRequestParams } from '../../sanitize_request_params'; import { AsyncSearchStatusResponse } from './types'; +import { shimHitsTotal, getTotalLoaded, IAsyncSearchOptions } from '../../../../common'; /** * Get the Kibana representation of an async search status response. @@ -35,16 +36,17 @@ export function toAsyncKibanaSearchStatusResponse( */ export function toAsyncKibanaSearchResponse( response: AsyncSearchResponse, - warning?: string, - requestParams?: ConnectionRequestParams + headers: IncomingHttpHeaders, + requestParams?: ConnectionRequestParams, + options?: IAsyncSearchOptions ): IKibanaSearchResponse { return { - id: response.id, - rawResponse: response.response, - isPartial: response.is_partial, - isRunning: response.is_running, - ...(warning ? { warning } : {}), + id: headers['x-elasticsearch-async-id'] as string, + rawResponse: response.response ? shimHitsTotal(response.response, options) : response, + isPartial: headers['x-elasticsearch-async-is-running'] === '?1', + isRunning: headers['x-elasticsearch-async-is-running'] === '?1', + ...(headers.warning ? { warning: headers.warning } : {}), ...(requestParams ? { requestParams: sanitizeRequestParams(requestParams) } : {}), - ...getTotalLoaded(response.response), + ...(response.response ? getTotalLoaded(response.response) : {}), }; } diff --git a/src/plugins/data/server/search/strategies/esql_async_search/esql_async_search_strategy.test.ts b/src/plugins/data/server/search/strategies/esql_async_search/esql_async_search_strategy.test.ts index f75d56a481ea..3d1f32e81a7f 100644 --- a/src/plugins/data/server/search/strategies/esql_async_search/esql_async_search_strategy.test.ts +++ b/src/plugins/data/server/search/strategies/esql_async_search/esql_async_search_strategy.test.ts @@ -29,6 +29,10 @@ const mockAsyncResponse = { }, }, }, + headers: { + 'x-elasticsearch-async-id': 'foo', + 'x-elasticsearch-async-is-running': '?0', + }, }; describe('ES|QL async search strategy', () => { diff --git a/src/plugins/data/server/search/strategies/esql_async_search/esql_async_search_strategy.ts b/src/plugins/data/server/search/strategies/esql_async_search/esql_async_search_strategy.ts index 83b67e5ecb4f..f8c686d8e4b9 100644 --- a/src/plugins/data/server/search/strategies/esql_async_search/esql_async_search_strategy.ts +++ b/src/plugins/data/server/search/strategies/esql_async_search/esql_async_search_strategy.ts @@ -14,6 +14,7 @@ import type { IKibanaSearchResponse, IKibanaSearchRequest } from '@kbn/search-ty import { SqlQueryRequest } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { SqlGetAsyncResponse } from '@elastic/elasticsearch/lib/api/types'; import type { ESQLSearchParams } from '@kbn/es-types'; +import { toAsyncKibanaSearchResponse } from './response_utils'; import { getCommonDefaultAsyncSubmitParams, getCommonDefaultAsyncGetParams, @@ -22,7 +23,6 @@ import { pollSearch } from '../../../../common'; import { getKbnSearchError } from '../../report_search_error'; import type { ISearchStrategy, SearchStrategyDependencies } from '../../types'; import type { IAsyncSearchOptions } from '../../../../common'; -import { toAsyncKibanaSearchResponse } from './response_utils'; import { SearchConfigSchema } from '../../../config'; // `drop_null_columns` is going to change the response @@ -74,14 +74,19 @@ export const esqlAsyncSearchStrategyProvider = ( ...(await getCommonDefaultAsyncSubmitParams(searchConfig, options)), ...requestParams, }; - const { body, headers, meta } = id + const response = id ? await client.transport.request( { method: 'GET', path: `/_query/async/${id}`, querystring: { ...params, drop_null_columns: dropNullColumns }, }, - { ...options.transport, signal: options.abortSignal, meta: true } + { + ...options.transport, + signal: options.abortSignal, + meta: true, + asStream: options.stream, + } ) : await client.transport.request( { @@ -90,16 +95,17 @@ export const esqlAsyncSearchStrategyProvider = ( body: params, querystring: dropNullColumns ? 'drop_null_columns' : '', }, - { ...options.transport, signal: options.abortSignal, meta: true } + { + ...options.transport, + signal: options.abortSignal, + meta: true, + asStream: options.stream, + } ); - const finalResponse = toAsyncKibanaSearchResponse( - body, - headers?.warning, - // do not return requestParams on polling calls - id ? undefined : meta?.request?.params - ); - return finalResponse; + const { body, headers, meta } = response; + + return toAsyncKibanaSearchResponse(body, headers, meta?.request?.params); }; const cancel = async () => { diff --git a/src/plugins/data/server/search/strategies/esql_async_search/response_utils.ts b/src/plugins/data/server/search/strategies/esql_async_search/response_utils.ts index 1c29906ea336..0d7a63529314 100644 --- a/src/plugins/data/server/search/strategies/esql_async_search/response_utils.ts +++ b/src/plugins/data/server/search/strategies/esql_async_search/response_utils.ts @@ -10,6 +10,7 @@ import type { ConnectionRequestParams } from '@elastic/transport'; import { SqlGetAsyncResponse } from '@elastic/elasticsearch/lib/api/types'; import type { IKibanaSearchResponse } from '@kbn/search-types'; +import { IncomingHttpHeaders } from 'http'; import { sanitizeRequestParams } from '../../sanitize_request_params'; /** @@ -17,17 +18,20 @@ import { sanitizeRequestParams } from '../../sanitize_request_params'; */ export function toAsyncKibanaSearchResponse( response: SqlGetAsyncResponse, - warning?: string, + headers: IncomingHttpHeaders, requestParams?: ConnectionRequestParams ): IKibanaSearchResponse { + const responseIsStream = response.id === undefined; return { - id: response.id, - rawResponse: { - ...response, - }, - isPartial: response.is_partial, - isRunning: response.is_running, - ...(warning ? { warning } : {}), + id: responseIsStream ? (headers['x-elasticsearch-async-id'] as string) : response.id, + rawResponse: response, + isRunning: responseIsStream + ? headers['x-elasticsearch-async-is-running'] === '?1' + : response.is_running, + isPartial: responseIsStream + ? headers['x-elasticsearch-async-is-partial'] === '?1' + : response.is_partial, + ...(headers?.warning ? { warning: headers?.warning } : {}), ...(requestParams ? { requestParams: sanitizeRequestParams(requestParams) } : {}), }; } diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx index bc9cad72a5eb..7784b8308053 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx @@ -20,12 +20,12 @@ import { import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { isOfAggregateQueryType } from '@kbn/es-query'; -import { appendWhereClauseToESQLQuery } from '@kbn/esql-utils'; +import { appendWhereClauseToESQLQuery, hasTransformationalCommand } from '@kbn/esql-utils'; import { METRIC_TYPE } from '@kbn/analytics'; import classNames from 'classnames'; import { generateFilters } from '@kbn/data-plugin/public'; import { useDragDropContext } from '@kbn/dom-drag-drop'; -import { DataViewType } from '@kbn/data-views-plugin/public'; +import { type DataViewField, DataViewType } from '@kbn/data-views-plugin/public'; import { SEARCH_FIELDS_FROM_SOURCE, SHOW_FIELD_STATISTICS, @@ -256,6 +256,21 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { const onFilter = isEsqlMode ? onPopulateWhereClause : onAddFilter; + const canSetBreakdownField = useMemo( + () => + isOfAggregateQueryType(query) + ? dataView?.isTimeBased() && !hasTransformationalCommand(query.esql) + : true, + [dataView, query] + ); + + const onAddBreakdownField = useCallback( + (field: DataViewField | undefined) => { + stateContainer.appState.update({ breakdownField: field?.name }); + }, + [stateContainer] + ); + const onFieldEdited = useCallback( async ({ removedFieldName }: { removedFieldName?: string } = {}) => { if (removedFieldName && currentColumns.includes(removedFieldName)) { @@ -423,18 +438,19 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { sidebarToggleState$={sidebarToggleState$} sidebarPanel={ } mainPanel={ diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.test.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.test.tsx index 6147bb916dad..296d403da690 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.test.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.test.tsx @@ -162,6 +162,7 @@ function getCompProps(options?: { hits?: DataTableRecord[] }): DiscoverSidebarRe result: hits, }) as DataDocuments$, onChangeDataView: jest.fn(), + onAddBreakdownField: jest.fn(), onAddFilter: jest.fn(), onAddField: jest.fn(), onRemoveField: jest.fn(), @@ -397,6 +398,19 @@ describe('discover responsive sidebar', function () { expect(ExistingFieldsServiceApi.loadFieldExisting).not.toHaveBeenCalled(); }); + it('should allow adding breakdown field', async function () { + const comp = await mountComponent(props); + const availableFields = findTestSubject(comp, 'fieldListGroupedAvailableFields'); + await act(async () => { + const button = findTestSubject(availableFields, 'field-extension-showDetails'); + button.simulate('click'); + comp.update(); + }); + + comp.update(); + findTestSubject(comp, 'fieldPopoverHeader_addBreakdownField-extension').simulate('click'); + expect(props.onAddBreakdownField).toHaveBeenCalled(); + }); it('should allow selecting fields', async function () { const comp = await mountComponent(props); const availableFields = findTestSubject(comp, 'fieldListGroupedAvailableFields'); diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx index 80a3b9d412c7..17a3e9def8b2 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx @@ -87,6 +87,10 @@ export interface DiscoverSidebarResponsiveProps { * hits fetched from ES, displayed in the doc table */ documents$: DataDocuments$; + /** + * Callback to update breakdown field + */ + onAddBreakdownField?: (breakdownField: DataViewField | undefined) => void; /** * Callback function when selecting a field */ @@ -151,6 +155,7 @@ export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps) selectedDataView, columns, trackUiMetric, + onAddBreakdownField, onAddFilter, onFieldEdited, onDataViewCreated, @@ -373,23 +378,24 @@ export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps) {selectedDataView ? ( ) : null} diff --git a/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx b/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx index 20ab07e1155c..26f056321553 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx @@ -8,8 +8,8 @@ */ import React, { useCallback, useEffect, useMemo, useRef } from 'react'; -import { type DataView, DataViewType } from '@kbn/data-views-plugin/public'; -import { DataViewPickerProps } from '@kbn/unified-search-plugin/public'; +import { DataViewType } from '@kbn/data-views-plugin/public'; +import type { DataViewPickerProps } from '@kbn/unified-search-plugin/public'; import { ENABLE_ESQL } from '@kbn/esql-utils'; import { TextBasedLanguages } from '@kbn/esql-utils'; import { DiscoverFlyouts, dismissAllFlyoutsExceptFor } from '@kbn/discover-utils'; @@ -20,7 +20,6 @@ import { useDiscoverServices } from '../../../../hooks/use_discover_services'; import type { DiscoverStateContainer } from '../../state_management/discover_state'; import { onSaveSearch } from './on_save_search'; import { useDiscoverCustomization } from '../../../../customizations'; -import { addLog } from '../../../../utils/add_log'; import { useAppStateSelector } from '../../state_management/discover_app_state_container'; import { useDiscoverTopNav } from './use_discover_topnav'; import { useIsEsqlMode } from '../../hooks/use_is_esql_mode'; @@ -47,15 +46,8 @@ export const DiscoverTopNav = ({ onCancelClick, }: DiscoverTopNavProps) => { const services = useDiscoverServices(); - const { - dataViewEditor, - navigation, - dataViewFieldEditor, - data, - uiSettings, - dataViews, - setHeaderActionMenu, - } = services; + const { dataViewEditor, navigation, dataViewFieldEditor, data, uiSettings, setHeaderActionMenu } = + services; const query = useAppStateSelector((state) => state.query); const adHocDataViews = useInternalStateSelector((state) => state.adHocDataViews); const dataView = useInternalStateSelector((state) => state.dataView!); @@ -93,7 +85,7 @@ export const DiscoverTopNav = ({ const editField = useMemo( () => canEditDataView - ? async (fieldName?: string, uiAction: 'edit' | 'add' = 'edit') => { + ? async (fieldName?: string) => { if (dataView?.id) { const dataViewInstance = await data.dataViews.get(dataView.id); closeFieldEditor.current = await dataViewFieldEditor.openEditor({ @@ -112,7 +104,7 @@ export const DiscoverTopNav = ({ ); const addField = useMemo( - () => (canEditDataView && editField ? () => editField(undefined, 'add') : undefined), + () => (canEditDataView && editField ? () => editField() : undefined), [editField, canEditDataView] ); @@ -123,23 +115,6 @@ export const DiscoverTopNav = ({ }); }, [dataViewEditor, stateContainer]); - const onEditDataView = useCallback( - async (editedDataView: DataView) => { - if (editedDataView.isPersisted()) { - // Clear the current data view from the cache and create a new instance - // of it, ensuring we have a new object reference to trigger a re-render - dataViews.clearInstanceCache(editedDataView.id); - stateContainer.actions.setDataView(await dataViews.create(editedDataView.toSpec(), true)); - } else { - await stateContainer.actions.updateAdHocDataViewId(); - } - stateContainer.actions.loadDataViewList(); - addLog('[DiscoverTopNav] onEditDataView triggers data fetching'); - stateContainer.dataState.fetch(); - }, - [dataViews, stateContainer.actions, stateContainer.dataState] - ); - const updateSavedQueryId = (newSavedQueryId: string | undefined) => { const { appState } = stateContainer; if (newSavedQueryId) { @@ -223,14 +198,13 @@ export const DiscoverTopNav = ({ textBasedLanguages: supportedTextBasedLanguages, adHocDataViews, savedDataViews, - onEditDataView, + onEditDataView: stateContainer.actions.onDataViewEdited, }; }, [ adHocDataViews, addField, createNewDataView, dataView, - onEditDataView, savedDataViews, stateContainer, uiSettings, 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 1fe833ba99af..46ecce387e87 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 @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { EuiBadge, EuiLink, EuiFlyout, EuiFlyoutBody } from '@elastic/eui'; +import { EuiBadge, EuiLink, EuiFlyout, EuiPanel } from '@elastic/eui'; import { AppMenuActionId, AppMenuActionType, @@ -89,12 +89,12 @@ export const createExampleDataSourceProfileProvider = (): DataSourceProfileProvi title: 'Example', order: 0, component: () => ( - +
    Example Doc View
                         {context.formatRecord(params.record.flattened)}
                       
    -
    + ), }); diff --git a/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.tsx b/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.tsx index b83ebbcb49d6..b334dbcb5857 100644 --- a/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.tsx +++ b/src/plugins/embeddable/public/add_panel_flyout/add_panel_flyout.tsx @@ -189,7 +189,7 @@ export const AddPanelFlyout = ({ return ( <> - +

    {i18n.translate('embeddableApi.addPanel.Title', { defaultMessage: 'Add from library' })}

    diff --git a/src/plugins/embeddable/public/add_panel_flyout/open_add_panel_flyout.tsx b/src/plugins/embeddable/public/add_panel_flyout/open_add_panel_flyout.tsx index 160289d0d1c2..9ba3c00a7374 100644 --- a/src/plugins/embeddable/public/add_panel_flyout/open_add_panel_flyout.tsx +++ b/src/plugins/embeddable/public/add_panel_flyout/open_add_panel_flyout.tsx @@ -52,6 +52,9 @@ export const openAddPanelFlyout = ({ if (onClose) onClose(); overlayRef.close(); }, + size: 'm', + maxWidth: 500, + paddingSize: 'm', 'data-test-subj': 'dashboardAddPanel', 'aria-labelledby': modalTitleId, } diff --git a/src/plugins/es_ui_shared/static/forms/helpers/field_validators/empty_field.test.ts b/src/plugins/es_ui_shared/static/forms/helpers/field_validators/empty_field.test.ts new file mode 100644 index 000000000000..e05f7c86b8a6 --- /dev/null +++ b/src/plugins/es_ui_shared/static/forms/helpers/field_validators/empty_field.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 { ValidationFuncArg } from '../../hook_form_lib'; +import { emptyField } from './empty_field'; + +describe('emptyField', () => { + const message = 'test error message'; + const code = 'ERR_FIELD_MISSING'; + const path = 'path'; + + const validator = (value: string | any[], trimString?: boolean) => + emptyField(message, trimString)({ value, path } as ValidationFuncArg); + + test('should return Validation function if value is an empty string and trimString is true', () => { + expect(validator('')).toMatchObject({ message, code, path }); + }); + + test('should return Validation function if value is an empty string and trimString is false', () => { + expect(validator('', false)).toMatchObject({ message, code, path }); + }); + + test('should return Validation function if value is a space and trimString is true', () => { + expect(validator(' ')).toMatchObject({ message, code, path }); + }); + + test('should return undefined if value is a space and trimString is false', () => { + expect(validator(' ', false)).toBeUndefined(); + }); + + test('should return undefined if value is a string and is not empty', () => { + expect(validator('not Empty')).toBeUndefined(); + }); + + test('should return undefined if value an array and is not empty', () => { + expect(validator(['not Empty'])).toBeUndefined(); + }); + + test('should return undefined if value an array and is empty', () => { + expect(validator([])).toMatchObject({ message, code, path }); + }); +}); diff --git a/src/plugins/es_ui_shared/static/forms/helpers/field_validators/empty_field.ts b/src/plugins/es_ui_shared/static/forms/helpers/field_validators/empty_field.ts index 3b09e165984d..9917b273d666 100644 --- a/src/plugins/es_ui_shared/static/forms/helpers/field_validators/empty_field.ts +++ b/src/plugins/es_ui_shared/static/forms/helpers/field_validators/empty_field.ts @@ -13,12 +13,14 @@ import { isEmptyArray } from '../../../validators/array'; import { ERROR_CODE } from './types'; export const emptyField = - (message: string) => + (message: string, trimString: boolean = true) => (...args: Parameters): ReturnType> => { const [{ value, path }] = args; if (typeof value === 'string') { - return isEmptyString(value) ? { code: 'ERR_FIELD_MISSING', path, message } : undefined; + return isEmptyString(value, trimString) + ? { code: 'ERR_FIELD_MISSING', path, message } + : undefined; } if (Array.isArray(value)) { diff --git a/src/plugins/es_ui_shared/static/validators/string/is_empty.ts b/src/plugins/es_ui_shared/static/validators/string/is_empty.ts index f70cbd36213e..197d707f5edb 100644 --- a/src/plugins/es_ui_shared/static/validators/string/is_empty.ts +++ b/src/plugins/es_ui_shared/static/validators/string/is_empty.ts @@ -7,4 +7,5 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export const isEmptyString = (value: string) => value.trim() === ''; +export const isEmptyString = (value: string, trimString: boolean = true) => + (trimString ? value.trim() : value) === ''; diff --git a/src/plugins/esql/kibana.jsonc b/src/plugins/esql/kibana.jsonc index 2bb2b759dc42..6ee732ef79f5 100644 --- a/src/plugins/esql/kibana.jsonc +++ b/src/plugins/esql/kibana.jsonc @@ -2,6 +2,8 @@ "type": "plugin", "id": "@kbn/esql", "owner": "@elastic/kibana-esql", + "group": "platform", + "visibility": "shared", "plugin": { "id": "esql", "server": true, diff --git a/src/plugins/esql_datagrid/kibana.jsonc b/src/plugins/esql_datagrid/kibana.jsonc index e2596ccb9fc8..f8f880b2d431 100644 --- a/src/plugins/esql_datagrid/kibana.jsonc +++ b/src/plugins/esql_datagrid/kibana.jsonc @@ -2,6 +2,8 @@ "type": "plugin", "id": "@kbn/esql-datagrid", "owner": "@elastic/kibana-esql", + "group": "platform", + "visibility": "shared", "plugin": { "id": "esqlDataGrid", "server": false, diff --git a/src/plugins/ftr_apis/server/routes/kbn_client_so/bulk_delete.ts b/src/plugins/ftr_apis/server/routes/kbn_client_so/bulk_delete.ts index b1667bfed4b9..7ba0a504fa53 100644 --- a/src/plugins/ftr_apis/server/routes/kbn_client_so/bulk_delete.ts +++ b/src/plugins/ftr_apis/server/routes/kbn_client_so/bulk_delete.ts @@ -15,8 +15,10 @@ export const registerBulkDeleteRoute = (router: IRouter) => { router.post( { path: `${KBN_CLIENT_API_PREFIX}/_bulk_delete`, - options: { - tags: ['access:ftrApis'], + security: { + authz: { + requiredPrivileges: ['ftrApis'], + }, }, validate: { body: schema.arrayOf( diff --git a/src/plugins/ftr_apis/server/routes/kbn_client_so/clean.ts b/src/plugins/ftr_apis/server/routes/kbn_client_so/clean.ts index 86be3af46348..2f2edc66fdc4 100644 --- a/src/plugins/ftr_apis/server/routes/kbn_client_so/clean.ts +++ b/src/plugins/ftr_apis/server/routes/kbn_client_so/clean.ts @@ -15,8 +15,10 @@ export const registerCleanRoute = (router: IRouter) => { router.post( { path: `${KBN_CLIENT_API_PREFIX}/_clean`, - options: { - tags: ['access:ftrApis'], + security: { + authz: { + requiredPrivileges: ['ftrApis'], + }, }, validate: { body: schema.object({ diff --git a/src/plugins/ftr_apis/server/routes/kbn_client_so/create.ts b/src/plugins/ftr_apis/server/routes/kbn_client_so/create.ts index 528e271de1d4..fdf93e2d517b 100644 --- a/src/plugins/ftr_apis/server/routes/kbn_client_so/create.ts +++ b/src/plugins/ftr_apis/server/routes/kbn_client_so/create.ts @@ -15,8 +15,10 @@ export const registerCreateRoute = (router: IRouter) => { router.post( { path: `${KBN_CLIENT_API_PREFIX}/{type}/{id?}`, - options: { - tags: ['access:ftrApis'], + security: { + authz: { + requiredPrivileges: ['ftrApis'], + }, }, validate: { params: schema.object({ diff --git a/src/plugins/ftr_apis/server/routes/kbn_client_so/delete.ts b/src/plugins/ftr_apis/server/routes/kbn_client_so/delete.ts index 77cec6243711..69bc5f51db11 100644 --- a/src/plugins/ftr_apis/server/routes/kbn_client_so/delete.ts +++ b/src/plugins/ftr_apis/server/routes/kbn_client_so/delete.ts @@ -15,8 +15,10 @@ export const registerDeleteRoute = (router: IRouter) => { router.delete( { path: `${KBN_CLIENT_API_PREFIX}/{type}/{id}`, - options: { - tags: ['access:ftrApis'], + security: { + authz: { + requiredPrivileges: ['ftrApis'], + }, }, validate: { params: schema.object({ diff --git a/src/plugins/ftr_apis/server/routes/kbn_client_so/find.ts b/src/plugins/ftr_apis/server/routes/kbn_client_so/find.ts index 2aefd0f87d33..ecacba6b782c 100644 --- a/src/plugins/ftr_apis/server/routes/kbn_client_so/find.ts +++ b/src/plugins/ftr_apis/server/routes/kbn_client_so/find.ts @@ -15,8 +15,10 @@ export const registerFindRoute = (router: IRouter) => { router.get( { path: `${KBN_CLIENT_API_PREFIX}/_find`, - options: { - tags: ['access:ftrApis'], + security: { + authz: { + requiredPrivileges: ['ftrApis'], + }, }, validate: { query: schema.object({ diff --git a/src/plugins/ftr_apis/server/routes/kbn_client_so/get.ts b/src/plugins/ftr_apis/server/routes/kbn_client_so/get.ts index bcfcd906ffc4..88685608aee1 100644 --- a/src/plugins/ftr_apis/server/routes/kbn_client_so/get.ts +++ b/src/plugins/ftr_apis/server/routes/kbn_client_so/get.ts @@ -15,8 +15,10 @@ export const registerGetRoute = (router: IRouter) => { router.get( { path: `${KBN_CLIENT_API_PREFIX}/{type}/{id}`, - options: { - tags: ['access:ftrApis'], + security: { + authz: { + requiredPrivileges: ['ftrApis'], + }, }, validate: { params: schema.object({ diff --git a/src/plugins/ftr_apis/server/routes/kbn_client_so/update.ts b/src/plugins/ftr_apis/server/routes/kbn_client_so/update.ts index ee5b90e2897e..e2eef65c0ec2 100644 --- a/src/plugins/ftr_apis/server/routes/kbn_client_so/update.ts +++ b/src/plugins/ftr_apis/server/routes/kbn_client_so/update.ts @@ -15,8 +15,10 @@ export const registerUpdateRoute = (router: IRouter) => { router.put( { path: `${KBN_CLIENT_API_PREFIX}/{type}/{id}`, - options: { - tags: ['access:ftrApis'], + security: { + authz: { + requiredPrivileges: ['ftrApis'], + }, }, validate: { params: schema.object({ diff --git a/src/plugins/home/server/routes/fetch_es_hits_status.ts b/src/plugins/home/server/routes/fetch_es_hits_status.ts index f01660876210..aa4c1286ce67 100644 --- a/src/plugins/home/server/routes/fetch_es_hits_status.ts +++ b/src/plugins/home/server/routes/fetch_es_hits_status.ts @@ -14,6 +14,12 @@ export const registerHitsStatusRoute = (router: IRouter) => { router.post( { path: '/api/home/hits_status', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { body: schema.object({ index: schema.string(), diff --git a/src/plugins/image_embeddable/public/components/image_editor/image_editor_flyout.test.tsx b/src/plugins/image_embeddable/public/components/image_editor/image_editor_flyout.test.tsx index 265f162d04f6..f052f0526a94 100644 --- a/src/plugins/image_embeddable/public/components/image_editor/image_editor_flyout.test.tsx +++ b/src/plugins/image_embeddable/public/components/image_editor/image_editor_flyout.test.tsx @@ -43,11 +43,11 @@ const ImageEditor = (props: Partial) => { ); }; -test('should call onCancel when "Close" clicked', async () => { +test('should call onCancel when "Cancel" clicked', async () => { const onCancel = jest.fn(); const { getByText } = render(); - expect(getByText('Close')).toBeVisible(); - await userEvent.click(getByText('Close')); + expect(getByText('Cancel')).toBeVisible(); + await userEvent.click(getByText('Cancel')); expect(onCancel).toBeCalled(); }); 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 2c57f25db6c8..1a5ee3bc64e1 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 @@ -121,7 +121,7 @@ export function ImageEditorFlyout(props: ImageEditorFlyoutProps) { return ( <> - +

    {isEditing ? ( - - + + + setSrcType('file')} isSelected={srcType === 'file'}> - - + {srcType === 'file' && ( <> {isDraftImageConfigValid ? ( @@ -238,7 +238,7 @@ export function ImageEditorFlyout(props: ImageEditorFlyoutProps) { />

    } - titleSize={'s'} + titleSize={'xs'} /> ) : ( )} - - + )} - - - - - - + diff --git a/src/plugins/image_embeddable/public/components/image_editor/open_image_editor.tsx b/src/plugins/image_embeddable/public/components/image_editor/open_image_editor.tsx index ae8ced88d14e..f730147cb0d2 100644 --- a/src/plugins/image_embeddable/public/components/image_editor/open_image_editor.tsx +++ b/src/plugins/image_embeddable/public/components/image_editor/open_image_editor.tsx @@ -79,6 +79,9 @@ export const openImageEditor = async ({ onClose: () => { onCancel(); }, + size: 'm', + maxWidth: 500, + paddingSize: 'm', ownFocus: true, 'data-test-subj': 'createImageEmbeddableFlyout', } diff --git a/src/plugins/interactive_setup/server/routes/configure.ts b/src/plugins/interactive_setup/server/routes/configure.ts index 1cdaf588a6cd..bb5a85800e03 100644 --- a/src/plugins/interactive_setup/server/routes/configure.ts +++ b/src/plugins/interactive_setup/server/routes/configure.ts @@ -37,6 +37,13 @@ export function defineConfigureRoute({ router.post( { path: '/internal/interactive_setup/configure', + security: { + authz: { + enabled: false, + reason: + 'Interactive setup is strictly a "pre-boot" feature which cannot leverage conventional authorization.', + }, + }, validate: { body: schema.object({ host: schema.uri({ scheme: ['http', 'https'] }), diff --git a/src/plugins/interactive_setup/server/routes/enroll.ts b/src/plugins/interactive_setup/server/routes/enroll.ts index 1cd0362d2790..7ee97db592ac 100644 --- a/src/plugins/interactive_setup/server/routes/enroll.ts +++ b/src/plugins/interactive_setup/server/routes/enroll.ts @@ -40,6 +40,13 @@ export function defineEnrollRoutes({ router.post( { path: '/internal/interactive_setup/enroll', + security: { + authz: { + enabled: false, + reason: + 'Interactive setup is strictly a "pre-boot" feature which cannot leverage conventional authorization.', + }, + }, validate: { body: schema.object({ hosts: schema.arrayOf(schema.uri({ scheme: 'https' }), { diff --git a/src/plugins/interactive_setup/server/routes/ping.ts b/src/plugins/interactive_setup/server/routes/ping.ts index 4deaeee67540..4c71d9f05bd1 100644 --- a/src/plugins/interactive_setup/server/routes/ping.ts +++ b/src/plugins/interactive_setup/server/routes/ping.ts @@ -17,6 +17,13 @@ export function definePingRoute({ router, logger, elasticsearch, preboot }: Rout router.post( { path: '/internal/interactive_setup/ping', + security: { + authz: { + enabled: false, + reason: + 'Interactive setup is strictly a "pre-boot" feature which cannot leverage conventional authorization.', + }, + }, validate: { body: schema.object({ host: schema.uri({ scheme: ['http', 'https'] }), diff --git a/src/plugins/interactive_setup/server/routes/status.ts b/src/plugins/interactive_setup/server/routes/status.ts index 78a97ac86231..14c94411ded5 100644 --- a/src/plugins/interactive_setup/server/routes/status.ts +++ b/src/plugins/interactive_setup/server/routes/status.ts @@ -15,6 +15,13 @@ export function defineStatusRoute({ router, elasticsearch, preboot }: RouteDefin router.get( { path: '/internal/interactive_setup/status', + security: { + authz: { + enabled: false, + reason: + 'Interactive setup is strictly a "pre-boot" feature which cannot leverage conventional authorization.', + }, + }, validate: false, options: { authRequired: false }, }, diff --git a/src/plugins/interactive_setup/server/routes/verify.ts b/src/plugins/interactive_setup/server/routes/verify.ts index a40e35794fb9..7fb5bb2e70c1 100644 --- a/src/plugins/interactive_setup/server/routes/verify.ts +++ b/src/plugins/interactive_setup/server/routes/verify.ts @@ -15,6 +15,13 @@ export function defineVerifyRoute({ router, verificationCode }: RouteDefinitionP router.post( { path: '/internal/interactive_setup/verify', + security: { + authz: { + enabled: false, + reason: + 'Interactive setup is strictly a "pre-boot" feature which cannot leverage conventional authorization.', + }, + }, validate: { body: schema.object({ code: schema.string(), diff --git a/src/plugins/kibana_usage_collection/server/collectors/core/core_usage_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/core/core_usage_collector.ts index b969215f508d..41e7bf9fd740 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/core/core_usage_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/core/core_usage_collector.ts @@ -1183,6 +1183,18 @@ export function getCoreUsageCollector( 'How many times a saved object has resolved with any of the four possible outcomes.', }, }, + 'deprecated_api_calls_resolved.total': { + type: 'integer', + _meta: { + description: 'How many times deprecated APIs has been marked as resolved', + }, + }, + 'deprecated_api_calls.total': { + type: 'integer', + _meta: { + description: 'How many times deprecated APIs has been called.', + }, + }, }, fetch() { return getCoreUsageDataService().getCoreUsageData(); diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index 779150faa89f..e3374219b655 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -578,10 +578,6 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, - 'metrics:allowCheckingForFailedShards': { - type: 'boolean', - _meta: { description: 'Non-default value of setting.' }, - }, 'observability:apmDefaultServiceEnvironment': { type: 'keyword', _meta: { description: 'Default value of the setting was changed.' }, 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 2734ab630431..b49647c3d479 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -152,7 +152,6 @@ export interface UsageStats { 'discover:rowHeightOption': number; hideAnnouncements: boolean; isDefaultIndexMigrated: boolean; - 'metrics:allowCheckingForFailedShards': boolean; 'observability:syntheticsThrottlingEnabled': boolean; 'observability:enableLegacyUptimeApp': boolean; 'observability:apmLabsButton': boolean; diff --git a/src/plugins/links/public/components/dashboard_link/dashboard_link_destination_picker.tsx b/src/plugins/links/public/components/dashboard_link/dashboard_link_destination_picker.tsx index b062b9befa28..ab5b92332704 100644 --- a/src/plugins/links/public/components/dashboard_link/dashboard_link_destination_picker.tsx +++ b/src/plugins/links/public/components/dashboard_link/dashboard_link_destination_picker.tsx @@ -119,6 +119,7 @@ export const DashboardLinkDestinationPicker = ({ return ( onClose()} > - +

    {link ? LinksStrings.editor.getEditLinkTitle() @@ -113,6 +113,7 @@ export const LinkEditor = ({ { @@ -131,6 +132,7 @@ export const LinkEditor = ({ /> onClose()} - iconType="cross" data-test-subj="links--linkEditor--closeBtn" > {LinksStrings.editor.getCancelButtonLabel()} @@ -160,6 +162,7 @@ export const LinkEditor = ({ { // this check should always be true, since the button is disabled otherwise - this is just for type safety diff --git a/src/plugins/links/public/components/editor/links_editor.scss b/src/plugins/links/public/components/editor/links_editor.scss index 02961c7d5f5c..c33b95350df9 100644 --- a/src/plugins/links/public/components/editor/links_editor.scss +++ b/src/plugins/links/public/components/editor/links_editor.scss @@ -3,7 +3,7 @@ .linksPanelEditor { .linkEditor { @include euiFlyout; - max-inline-size: $euiSizeXXL * 18; // 40px * 18 = 720px + max-inline-size: $euiSizeXS * 125; // 4px * 125 = 500px &.in { animation: euiFlyoutOpenAnimation $euiAnimSpeedNormal $euiAnimSlightResistance; @@ -59,6 +59,9 @@ } .links_hoverActions { + background-color: $euiColorEmptyShade; + position: absolute; + right: $euiSizeL; opacity: 0; visibility: hidden; transition: visibility $euiAnimSpeedNormal, opacity $euiAnimSpeedNormal; diff --git a/src/plugins/links/public/components/editor/links_editor.tsx b/src/plugins/links/public/components/editor/links_editor.tsx index 93ca47e364c5..8fa33fd4ebca 100644 --- a/src/plugins/links/public/components/editor/links_editor.tsx +++ b/src/plugins/links/public/components/editor/links_editor.tsx @@ -167,7 +167,7 @@ const LinksEditor = ({ - +

    {isEditingExisting ? LinksStrings.editor.panelEditor.getEditFlyoutTitle() @@ -251,7 +251,6 @@ const LinksEditor = ({ @@ -268,6 +267,7 @@ const LinksEditor = ({ data-test-subj="links--panelEditor--saveByReferenceTooltip" > - - - - - - - - - - - - - - + + + + + + + + + + + + ); diff --git a/src/plugins/links/public/components/external_link/external_link_destination_picker.tsx b/src/plugins/links/public/components/external_link/external_link_destination_picker.tsx index dfdc6e0589e6..5b8522b39960 100644 --- a/src/plugins/links/public/components/external_link/external_link_destination_picker.tsx +++ b/src/plugins/links/public/components/external_link/external_link_destination_picker.tsx @@ -54,6 +54,7 @@ export const ExternalLinkDestinationPicker = ({ return (
    i18n.translate('links.editor.cancelButtonLabel', { - defaultMessage: 'Close', + defaultMessage: 'Cancel', }), panelEditor: { getLinksTitle: () => diff --git a/src/plugins/links/public/editor/open_editor_flyout.tsx b/src/plugins/links/public/editor/open_editor_flyout.tsx index 041672e89dbb..87b1ab4e21ff 100644 --- a/src/plugins/links/public/editor/open_editor_flyout.tsx +++ b/src/plugins/links/public/editor/open_editor_flyout.tsx @@ -137,7 +137,8 @@ export async function openEditorFlyout({ ), { id: flyoutId, - maxWidth: 720, + maxWidth: 500, + paddingSize: 'm', ownFocus: true, onClose: onCancel, outsideClickCloses: false, diff --git a/src/plugins/links/public/types.ts b/src/plugins/links/public/types.ts index 97b1f0254f4e..df3eb7fc2b51 100644 --- a/src/plugins/links/public/types.ts +++ b/src/plugins/links/public/types.ts @@ -22,7 +22,7 @@ import { DynamicActionsSerializedState } from '@kbn/embeddable-enhanced-plugin/p import { HasSerializedChildState, PresentationContainer } from '@kbn/presentation-containers'; import { LocatorPublic } from '@kbn/share-plugin/common'; import { DashboardLocatorParams, DASHBOARD_CONTAINER_TYPE } from '@kbn/dashboard-plugin/public'; -import { DashboardAttributes } from '@kbn/dashboard-plugin/common'; +import type { DashboardAttributes } from '@kbn/dashboard-plugin/server'; import { CONTENT_ID } from '../common'; import { Link, LinksAttributes, LinksLayoutType } from '../common/content_management'; @@ -73,5 +73,5 @@ export type ResolvedLink = Link & { export interface DashboardItem { id: string; - attributes: DashboardAttributes; + attributes: Pick; } diff --git a/src/plugins/presentation_util/public/components/dashboard_drilldown_options/dashboard_drilldown_options.tsx b/src/plugins/presentation_util/public/components/dashboard_drilldown_options/dashboard_drilldown_options.tsx index 921560f7a222..63ff89da2ec1 100644 --- a/src/plugins/presentation_util/public/components/dashboard_drilldown_options/dashboard_drilldown_options.tsx +++ b/src/plugins/presentation_util/public/components/dashboard_drilldown_options/dashboard_drilldown_options.tsx @@ -8,7 +8,7 @@ */ import React from 'react'; -import { EuiFormRow, EuiSwitch } from '@elastic/eui'; +import { EuiFormRow, EuiSpacer, EuiSwitch } from '@elastic/eui'; import { DashboardDrilldownOptions } from './types'; import { dashboardDrilldownConfigStrings } from '../../i18n/dashboard_drilldown_config'; @@ -24,32 +24,35 @@ export const DashboardDrilldownOptionsComponent = ({ }: DashboardDrilldownOptionsProps) => { return ( <> - - onOptionChange({ useCurrentFilters: !options.useCurrentFilters })} - data-test-subj="dashboardDrillDownOptions--useCurrentFilters--checkbox" - /> - - - onOptionChange({ useCurrentDateRange: !options.useCurrentDateRange })} - data-test-subj="dashboardDrillDownOptions--useCurrentDateRange--checkbox" - /> - - - onOptionChange({ openInNewTab: !options.openInNewTab })} - data-test-subj="dashboardDrillDownOptions--openInNewTab--checkbox" - /> + +
    + onOptionChange({ useCurrentFilters: !options.useCurrentFilters })} + data-test-subj="dashboardDrillDownOptions--useCurrentFilters--checkbox" + /> + + onOptionChange({ useCurrentDateRange: !options.useCurrentDateRange })} + data-test-subj="dashboardDrillDownOptions--useCurrentDateRange--checkbox" + /> + + onOptionChange({ openInNewTab: !options.openInNewTab })} + data-test-subj="dashboardDrillDownOptions--openInNewTab--checkbox" + /> +
    ); diff --git a/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.tsx b/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.tsx index e985e9bec357..1c8466097bd9 100644 --- a/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.tsx +++ b/src/plugins/presentation_util/public/components/data_view_picker/data_view_picker.tsx @@ -52,6 +52,7 @@ export function DataViewPicker({ data-test-subj="open-data-view-picker" onClick={() => setPopoverIsOpen(!isPopoverOpen)} label={label} + size="s" fullWidth {...colorProp} {...rest} diff --git a/src/plugins/presentation_util/public/components/field_picker/field_picker.tsx b/src/plugins/presentation_util/public/components/field_picker/field_picker.tsx index daac202f21b6..0b81cfd66156 100644 --- a/src/plugins/presentation_util/public/components/field_picker/field_picker.tsx +++ b/src/plugins/presentation_util/public/components/field_picker/field_picker.tsx @@ -140,6 +140,7 @@ export const FieldPicker = ({ placeholder: i18n.translate('presentationUtil.fieldSearch.searchPlaceHolder', { defaultMessage: 'Search field names', }), + compressed: true, disabled: Boolean(selectableProps?.isLoading), inputRef: setSearchRef, }} diff --git a/src/plugins/presentation_util/public/components/field_picker/field_type_filter.tsx b/src/plugins/presentation_util/public/components/field_picker/field_type_filter.tsx index d2e929b8a9a8..4212668599a0 100644 --- a/src/plugins/presentation_util/public/components/field_picker/field_type_filter.tsx +++ b/src/plugins/presentation_util/public/components/field_picker/field_type_filter.tsx @@ -63,7 +63,7 @@ export function FieldTypeFilter({ ); return ( - +
    { router.post( { path: '/internal/kibana/management/saved_objects/_bulk_delete', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { body: schema.arrayOf( schema.object({ diff --git a/src/plugins/saved_objects_management/server/routes/bulk_get.ts b/src/plugins/saved_objects_management/server/routes/bulk_get.ts index 9b7c1505cc69..59efd552196c 100644 --- a/src/plugins/saved_objects_management/server/routes/bulk_get.ts +++ b/src/plugins/saved_objects_management/server/routes/bulk_get.ts @@ -20,6 +20,12 @@ export const registerBulkGetRoute = ( router.post( { path: '/api/kibana/management/saved_objects/_bulk_get', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { body: schema.arrayOf( schema.object({ diff --git a/src/plugins/saved_objects_management/server/routes/find.ts b/src/plugins/saved_objects_management/server/routes/find.ts index 8b37c3550f7d..e1c028a4fab2 100644 --- a/src/plugins/saved_objects_management/server/routes/find.ts +++ b/src/plugins/saved_objects_management/server/routes/find.ts @@ -34,6 +34,12 @@ export const registerFindRoute = ( router.get( { path: '/api/kibana/management/saved_objects/_find', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { query: schema.object({ perPage: schema.number({ min: 0, defaultValue: 20 }), diff --git a/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts b/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts index c484f5643d8c..6b89643e8142 100644 --- a/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts +++ b/src/plugins/saved_objects_management/server/routes/get_allowed_types.ts @@ -23,6 +23,12 @@ export const registerGetAllowedTypesRoute = (router: IRouter) => { router.get( { path: '/api/kibana/management/saved_objects/_allowed_types', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: false, }, async (context, req, res) => { diff --git a/src/plugins/saved_objects_management/server/routes/relationships.ts b/src/plugins/saved_objects_management/server/routes/relationships.ts index 7f06e6a5dabc..d39f001f2f2a 100644 --- a/src/plugins/saved_objects_management/server/routes/relationships.ts +++ b/src/plugins/saved_objects_management/server/routes/relationships.ts @@ -21,6 +21,12 @@ export const registerRelationshipsRoute = ( router.get( { path: '/api/kibana/management/saved_objects/relationships/{type}/{id}', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { params: schema.object({ type: schema.string(), diff --git a/src/plugins/saved_objects_management/server/routes/scroll_count.ts b/src/plugins/saved_objects_management/server/routes/scroll_count.ts index 31c01536d600..3116ca3a22fb 100644 --- a/src/plugins/saved_objects_management/server/routes/scroll_count.ts +++ b/src/plugins/saved_objects_management/server/routes/scroll_count.ts @@ -17,6 +17,12 @@ export const registerScrollForCountRoute = (router: IRouter) => { router.post( { path: '/api/kibana/management/saved_objects/scroll/counts', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { body: schema.object({ typesToInclude: schema.arrayOf(schema.string()), diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index d54a75b313cd..6a4317749254 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -9290,6 +9290,18 @@ "_meta": { "description": "How many times a saved object has resolved with any of the four possible outcomes." } + }, + "deprecated_api_calls_resolved.total": { + "type": "integer", + "_meta": { + "description": "How many times deprecated APIs has been marked as resolved" + } + }, + "deprecated_api_calls.total": { + "type": "integer", + "_meta": { + "description": "How many times deprecated APIs has been called." + } } } }, @@ -10719,12 +10731,6 @@ "description": "Non-default value of setting." } }, - "metrics:allowCheckingForFailedShards": { - "type": "boolean", - "_meta": { - "description": "Non-default value of setting." - } - }, "observability:apmDefaultServiceEnvironment": { "type": "keyword", "_meta": { @@ -10893,12 +10899,6 @@ "description": "Non-default value of setting." } }, - "observability:newLogsOverview": { - "type": "boolean", - "_meta": { - "description": "Enable the new logs overview component." - } - }, "observability:searchExcludedDataTiers": { "type": "array", "items": { @@ -10907,6 +10907,12 @@ "description": "Non-default value of setting." } } + }, + "observability:newLogsOverview": { + "type": "boolean", + "_meta": { + "description": "Enable the new logs overview component." + } } } }, diff --git a/src/plugins/telemetry/server/routes/telemetry_config.ts b/src/plugins/telemetry/server/routes/telemetry_config.ts index ebc5ca53985e..700e778ceea2 100644 --- a/src/plugins/telemetry/server/routes/telemetry_config.ts +++ b/src/plugins/telemetry/server/routes/telemetry_config.ts @@ -102,12 +102,46 @@ export function registerTelemetryConfigRoutes({ options: { authRequired: 'optional' }, }) // Just because it used to be /v2/, we are creating identical v1 and v2. - .addVersion({ version: '1', validate: v2Validations }, v2Handler) - .addVersion({ version: '2', validate: v2Validations }, v2Handler); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ) + .addVersion( + { + version: '2', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ); // Register the deprecated public and path-based for BWC // as we know this one is used by other Elastic products to fetch the opt-in status. - router.versioned - .get({ access: 'public', path: FetchTelemetryConfigRoutePathBasedV2 }) - .addVersion({ version: '2023-10-31', validate: v2Validations }, v2Handler); + router.versioned.get({ access: 'public', path: FetchTelemetryConfigRoutePathBasedV2 }).addVersion( + { + version: '2023-10-31', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ); } diff --git a/src/plugins/telemetry/server/routes/telemetry_last_reported.ts b/src/plugins/telemetry/server/routes/telemetry_last_reported.ts index 299d457e080b..932b7ab8db9c 100644 --- a/src/plugins/telemetry/server/routes/telemetry_last_reported.ts +++ b/src/plugins/telemetry/server/routes/telemetry_last_reported.ts @@ -40,8 +40,32 @@ export function registerTelemetryLastReported( router.versioned .get({ access: 'internal', path: LastReportedRoute }) // Just because it used to be /v2/, we are creating identical v1 and v2. - .addVersion({ version: '1', validate: v2GetValidations }, v2GetHandler) - .addVersion({ version: '2', validate: v2GetValidations }, v2GetHandler); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2GetValidations, + }, + v2GetHandler + ) + .addVersion( + { + version: '2', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2GetValidations, + }, + v2GetHandler + ); // PUT to update const v2PutHandler: RequestHandler = async (context, req, res) => { @@ -55,6 +79,30 @@ export function registerTelemetryLastReported( router.versioned .put({ access: 'internal', path: LastReportedRoute }) // Just because it used to be /v2/, we are creating identical v1 and v2. - .addVersion({ version: '1', validate: false }, v2PutHandler) - .addVersion({ version: '2', validate: false }, v2PutHandler); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, + v2PutHandler + ) + .addVersion( + { + version: '2', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, + v2PutHandler + ); } diff --git a/src/plugins/telemetry/server/routes/telemetry_opt_in.ts b/src/plugins/telemetry/server/routes/telemetry_opt_in.ts index 21b674c3dc45..de13162ff061 100644 --- a/src/plugins/telemetry/server/routes/telemetry_opt_in.ts +++ b/src/plugins/telemetry/server/routes/telemetry_opt_in.ts @@ -128,6 +128,30 @@ export function registerTelemetryOptInRoutes({ router.versioned .post({ access: 'internal', path: OptInRoute }) // Just because it used to be /v2/, we are creating identical v1 and v2. - .addVersion({ version: '1', validate: v2Validations }, v2Handler) - .addVersion({ version: '2', validate: v2Validations }, v2Handler); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ) + .addVersion( + { + version: '2', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ); } diff --git a/src/plugins/telemetry/server/routes/telemetry_opt_in_stats.ts b/src/plugins/telemetry/server/routes/telemetry_opt_in_stats.ts index dcd7790b67e6..0c38b5981850 100644 --- a/src/plugins/telemetry/server/routes/telemetry_opt_in_stats.ts +++ b/src/plugins/telemetry/server/routes/telemetry_opt_in_stats.ts @@ -72,6 +72,12 @@ export function registerTelemetryOptInStatsRoutes( .addVersion( { version: '2023-10-31', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { request: { body: schema.object({ diff --git a/src/plugins/telemetry/server/routes/telemetry_usage_stats.ts b/src/plugins/telemetry/server/routes/telemetry_usage_stats.ts index f19ec804ac6e..28198c853e4b 100644 --- a/src/plugins/telemetry/server/routes/telemetry_usage_stats.ts +++ b/src/plugins/telemetry/server/routes/telemetry_usage_stats.ts @@ -97,6 +97,30 @@ export function registerTelemetryUsageStatsRoutes( enableQueryVersion: true, // Allow specifying the version through querystring so that we can use it in Dev Console }) // Just because it used to be /v2/, we are creating identical v1 and v2. - .addVersion({ version: '1', validate: v2Validations }, v2Handler) - .addVersion({ version: '2', validate: v2Validations }, v2Handler); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ) + .addVersion( + { + version: '2', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: v2Validations, + }, + v2Handler + ); } diff --git a/src/plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts b/src/plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts index 54eaae80648e..dff8a8f2d5bd 100644 --- a/src/plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts +++ b/src/plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts @@ -56,6 +56,30 @@ export function registerTelemetryUserHasSeenNotice(router: IRouter, currentKiban router.versioned .put({ access: 'internal', path: UserHasSeenNoticeRoute }) // Just because it used to be /v2/, we are creating identical v1 and v2. - .addVersion({ version: '1', validate: false }, v2Handler) - .addVersion({ version: '2', validate: false }, v2Handler); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, + v2Handler + ) + .addVersion( + { + version: '2', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, + v2Handler + ); } diff --git a/src/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/url_drilldown_options.tsx b/src/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/url_drilldown_options.tsx index 449e7a7d6cca..faff3d4557b1 100644 --- a/src/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/url_drilldown_options.tsx +++ b/src/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/url_drilldown_collect_config/url_drilldown_options.tsx @@ -28,31 +28,34 @@ export const UrlDrilldownOptionsComponent = ({ }: UrlDrilldownOptionsProps) => { return ( <> - - onOptionChange({ openInNewTab: !options.openInNewTab })} - data-test-subj="urlDrilldownOpenInNewTab" - /> - - - - {txtUrlTemplateEncodeUrl} - - {txtUrlTemplateEncodeDescription} - - } - checked={options.encodeUrl} - onChange={() => onOptionChange({ encodeUrl: !options.encodeUrl })} - data-test-subj="urlDrilldownEncodeUrl" - /> + +
    + onOptionChange({ openInNewTab: !options.openInNewTab })} + data-test-subj="urlDrilldownOpenInNewTab" + /> + + + {txtUrlTemplateEncodeUrl} + + {txtUrlTemplateEncodeDescription} + + } + checked={options.encodeUrl} + onChange={() => onOptionChange({ encodeUrl: !options.encodeUrl })} + data-test-subj="urlDrilldownEncodeUrl" + /> +
    ); diff --git a/src/plugins/unified_histogram/public/chart/breakdown_field_selector.tsx b/src/plugins/unified_histogram/public/chart/breakdown_field_selector.tsx index 0d6aa1e75fe8..418892bd5434 100644 --- a/src/plugins/unified_histogram/public/chart/breakdown_field_selector.tsx +++ b/src/plugins/unified_histogram/public/chart/breakdown_field_selector.tsx @@ -9,7 +9,12 @@ import React, { useCallback, useMemo } from 'react'; import { EuiSelectableOption } from '@elastic/eui'; -import { FieldIcon, getFieldIconProps, comboBoxFieldOptionMatcher } from '@kbn/field-utils'; +import { + FieldIcon, + getFieldIconProps, + comboBoxFieldOptionMatcher, + fieldSupportsBreakdown, +} from '@kbn/field-utils'; import { css } from '@emotion/react'; import { isESQLColumnGroupable } from '@kbn/esql-utils'; import { type DataView, DataViewField } from '@kbn/data-views-plugin/common'; @@ -17,7 +22,6 @@ import type { DatatableColumn } from '@kbn/expressions-plugin/common'; import { convertDatatableColumnToDataViewFieldSpec } from '@kbn/data-view-utils'; import { i18n } from '@kbn/i18n'; import { UnifiedHistogramBreakdownContext } from '../types'; -import { fieldSupportsBreakdown } from '../utils/field_supports_breakdown'; import { ToolbarSelector, ToolbarSelectorProps, diff --git a/src/plugins/unified_histogram/public/index.ts b/src/plugins/unified_histogram/public/index.ts index fda59c78819d..f79db6ce8a51 100644 --- a/src/plugins/unified_histogram/public/index.ts +++ b/src/plugins/unified_histogram/public/index.ts @@ -36,6 +36,5 @@ export type { } from './types'; export { UnifiedHistogramFetchStatus, UnifiedHistogramExternalVisContextStatus } from './types'; export { canImportVisContext } from './utils/external_vis_context'; -export { fieldSupportsBreakdown } from './utils/field_supports_breakdown'; export const plugin = () => new UnifiedHistogramPublicPlugin(); 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 2367e729b5a7..04bf810848f2 100644 --- a/src/plugins/unified_histogram/public/services/lens_vis_service.ts +++ b/src/plugins/unified_histogram/public/services/lens_vis_service.ts @@ -36,6 +36,7 @@ import { LegendSize } from '@kbn/visualizations-plugin/public'; import { XYConfiguration } from '@kbn/visualizations-plugin/common'; import type { Datatable, DatatableColumn } from '@kbn/expressions-plugin/common'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { fieldSupportsBreakdown } from '@kbn/field-utils'; import { UnifiedHistogramExternalVisContextStatus, UnifiedHistogramSuggestionContext, @@ -49,7 +50,6 @@ import { injectESQLQueryIntoLensLayers, } from '../utils/external_vis_context'; import { computeInterval } from '../utils/compute_interval'; -import { fieldSupportsBreakdown } from '../utils/field_supports_breakdown'; import { shouldDisplayHistogram } from '../layout/helpers'; import { enrichLensAttributesWithTablesData } from '../utils/lens_vis_from_table'; diff --git a/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx b/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx index ade754004b8e..d89621d59867 100644 --- a/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx +++ b/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx @@ -43,6 +43,10 @@ const mapAdHocDataView = (adHocDataView: DataView): DataViewListItemEnhanced => }; }; +const shrinkableContainerCss = css` + min-width: 0; +`; + export function ChangeDataView({ isMissingCurrent, currentDataViewId, @@ -238,7 +242,7 @@ export function ChangeDataView({ return ( <> - + - + { collectionActions.handleChange = jest.fn(); const wrapper = mountWithIntl(); - const operatorInput = findTestSubject(wrapper, 'colorRuleOperator'); + const operatorInput = findTestSubject(wrapper, 'colorRuleOperator').find('input'); operatorInput.simulate('keyDown', { key: keys.ARROW_DOWN }); operatorInput.simulate('keyDown', { key: keys.ARROW_DOWN }); operatorInput.simulate('keyDown', { key: keys.ENTER }); diff --git a/src/plugins/vis_types/timeseries/public/metrics_type.ts b/src/plugins/vis_types/timeseries/public/metrics_type.ts index eec28bb6cf47..65150ab9eabe 100644 --- a/src/plugins/vis_types/timeseries/public/metrics_type.ts +++ b/src/plugins/vis_types/timeseries/public/metrics_type.ts @@ -24,9 +24,9 @@ import { extractIndexPatternValues, isStringTypeIndexPattern, } from '../common/index_patterns_utils'; -import { TSVB_DEFAULT_COLOR, UI_SETTINGS, VIS_TYPE } from '../common/constants'; +import { TSVB_DEFAULT_COLOR, VIS_TYPE } from '../common/constants'; import { toExpressionAst } from './to_ast'; -import { getDataViewsStart, getUISettings } from './services'; +import { getDataViewsStart } from './services'; import type { TimeseriesVisDefaultParams, TimeseriesVisParams } from './types'; import type { IndexPatternValue, Panel } from '../common/types'; @@ -188,6 +188,5 @@ export const metricsVisDefinition: VisTypeDefinition< requests: new RequestAdapter(), }), requiresSearch: true, - suppressWarnings: () => !getUISettings().get(UI_SETTINGS.ALLOW_CHECKING_FOR_FAILED_SHARDS), getUsedIndexPattern: getUsedIndexPatterns, }; diff --git a/src/plugins/vis_types/timeseries/server/ui_settings.ts b/src/plugins/vis_types/timeseries/server/ui_settings.ts index 0d3dcc681110..9d6ac0f0856d 100644 --- a/src/plugins/vis_types/timeseries/server/ui_settings.ts +++ b/src/plugins/vis_types/timeseries/server/ui_settings.ts @@ -38,18 +38,4 @@ export const getUiSettings: () => Record = () => ({ }), schema: schema.boolean(), }, - [UI_SETTINGS.ALLOW_CHECKING_FOR_FAILED_SHARDS]: { - name: i18n.translate('visTypeTimeseries.advancedSettings.allowCheckingForFailedShardsTitle', { - defaultMessage: 'Show TSVB request shard failures', - }), - value: true, - description: i18n.translate( - 'visTypeTimeseries.advancedSettings.allowCheckingForFailedShardsText', - { - defaultMessage: - 'Show warning message for partial data in TSVB charts if the request succeeds for some shards but fails for others.', - } - ), - schema: schema.boolean(), - }, }); diff --git a/src/plugins/visualizations/public/legacy/embeddable/visualize_embeddable.tsx b/src/plugins/visualizations/public/legacy/embeddable/visualize_embeddable.tsx index 4f6bfa344a0a..196753d73b28 100644 --- a/src/plugins/visualizations/public/legacy/embeddable/visualize_embeddable.tsx +++ b/src/plugins/visualizations/public/legacy/embeddable/visualize_embeddable.tsx @@ -353,10 +353,6 @@ export class VisualizeEmbeddable ); return true; } - if (this.vis.type.suppressWarnings?.()) { - // if the vis type wishes to supress all warnings, return true so the default logic won't pick it up - return true; - } }); } diff --git a/src/plugins/visualizations/public/vis_types/base_vis_type.ts b/src/plugins/visualizations/public/vis_types/base_vis_type.ts index f3a88245008e..e7519729eaa0 100644 --- a/src/plugins/visualizations/public/vis_types/base_vis_type.ts +++ b/src/plugins/visualizations/public/vis_types/base_vis_type.ts @@ -43,7 +43,6 @@ export class BaseVisType { public readonly disableCreate; public readonly disableEdit; public readonly requiresSearch; - public readonly suppressWarnings; public readonly hasPartialRows; public readonly hierarchicalData; public readonly setup; @@ -70,7 +69,6 @@ export class BaseVisType { this.icon = opts.icon; this.image = opts.image; this.order = opts.order ?? 0; - this.suppressWarnings = opts.suppressWarnings; this.visConfig = defaultsDeep({}, opts.visConfig, { defaults: {} }); this.editorConfig = defaultsDeep({}, opts.editorConfig, { collections: {} }); this.options = defaultsDeep({}, opts.options, defaultOptions); diff --git a/test/api_integration/apis/dashboards/create_dashboard/index.ts b/test/api_integration/apis/dashboards/create_dashboard/index.ts new file mode 100644 index 000000000000..c9c2f63dd3b8 --- /dev/null +++ b/test/api_integration/apis/dashboards/create_dashboard/index.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 kibanaServer = getService('kibanaServer'); + describe('dashboards - create', () => { + before(async () => { + await kibanaServer.importExport.load( + 'test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.unload( + 'test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + }); + loadTestFile(require.resolve('./main')); + loadTestFile(require.resolve('./validation')); + }); +} diff --git a/test/api_integration/apis/dashboards/create_dashboard/main.ts b/test/api_integration/apis/dashboards/create_dashboard/main.ts new file mode 100644 index 000000000000..3b8b71f827de --- /dev/null +++ b/test/api_integration/apis/dashboards/create_dashboard/main.ts @@ -0,0 +1,216 @@ +/* + * Copyright 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 { PUBLIC_API_PATH } from '@kbn/dashboard-plugin/server'; +import { DEFAULT_IGNORE_PARENT_SETTINGS } from '@kbn/controls-plugin/common'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + describe('main', () => { + it('sets top level default values', async () => { + const title = `foo-${Date.now()}-${Math.random()}`; + + const response = await supertest + .post(PUBLIC_API_PATH) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({ + attributes: { + title, + }, + }); + + expect(response.status).to.be(200); + expect(response.body.item.attributes.kibanaSavedObjectMeta.searchSource).to.eql({}); + expect(response.body.item.attributes.panels).to.eql([]); + expect(response.body.item.attributes.timeRestore).to.be(false); + expect(response.body.item.attributes.options).to.eql({ + hidePanelTitles: false, + useMargins: true, + syncColors: true, + syncTooltips: true, + syncCursor: true, + }); + }); + + it('sets panels default values', async () => { + const title = `foo-${Date.now()}-${Math.random()}`; + + const response = await supertest + .post(PUBLIC_API_PATH) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({ + attributes: { + title, + panels: [ + { + type: 'visualization', + gridData: { + x: 0, + y: 0, + w: 24, + h: 15, + }, + panelConfig: {}, + }, + ], + }, + }); + + expect(response.status).to.be(200); + expect(response.body.item.attributes.panels).to.be.an('array'); + // panel index is a random uuid when not provided + expect(response.body.item.attributes.panels[0].panelIndex).match(/^[0-9a-f-]{36}$/); + expect(response.body.item.attributes.panels[0].panelIndex).to.eql( + response.body.item.attributes.panels[0].gridData.i + ); + }); + + it('sets controls default values', async () => { + const title = `foo-${Date.now()}-${Math.random()}`; + + const response = await supertest + .post(PUBLIC_API_PATH) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({ + attributes: { + title, + controlGroupInput: { + controls: [ + { + type: 'optionsListControl', + order: 0, + width: 'medium', + grow: true, + controlConfig: { + title: 'Origin City', + fieldName: 'OriginCityName', + dataViewId: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', + selectedOptions: [], + enhancements: {}, + }, + }, + ], + }, + }, + }); + + expect(response.status).to.be(200); + // generates a random saved object id + expect(response.body.item.id).match(/^[0-9a-f-]{36}$/); + // saved object stores controls panels as an object, but the API should return as an array + expect(response.body.item.attributes.controlGroupInput.controls).to.be.an('array'); + + expect(response.body.item.attributes.controlGroupInput.ignoreParentSettings).to.eql( + DEFAULT_IGNORE_PARENT_SETTINGS + ); + }); + + it('can create a dashboard with a specific id', async () => { + const title = `foo-${Date.now()}-${Math.random()}`; + const id = `bar-${Date.now()}-${Math.random()}`; + + const response = await supertest + .post(`${PUBLIC_API_PATH}/${id}`) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({ + attributes: { title }, + }); + + expect(response.status).to.be(200); + expect(response.body.item.id).to.be(id); + }); + + it('creates a dashboard with references', async () => { + const title = `foo-${Date.now()}-${Math.random()}`; + + const response = await supertest + .post(PUBLIC_API_PATH) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({ + attributes: { + title, + panels: [ + { + type: 'visualization', + gridData: { + x: 0, + y: 0, + w: 24, + h: 15, + i: 'bizz', + }, + panelConfig: {}, + panelIndex: 'bizz', + panelRefName: 'panel_bizz', + }, + ], + }, + references: [ + { + name: 'bizz:panel_bizz', + type: 'visualization', + id: 'my-saved-object', + }, + ], + }); + + expect(response.status).to.be(200); + expect(response.body.item.attributes.panels).to.be.an('array'); + }); + + // TODO Maybe move this test to x-pack/test/api_integration/dashboards + it('can create a dashboard in a defined space', async () => { + const title = `foo-${Date.now()}-${Math.random()}`; + + const spaceId = 'space-1'; + + const response = await supertest + .post(`/s/${spaceId}${PUBLIC_API_PATH}`) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({ + attributes: { + title, + }, + spaces: [spaceId], + }); + + expect(response.status).to.be(200); + expect(response.body.item.namespaces).to.eql([spaceId]); + }); + + it('return error if provided id already exists', async () => { + const title = `foo-${Date.now()}-${Math.random()}`; + // id is a saved object loaded by the kbn_archiver + const id = 'be3733a0-9efe-11e7-acb3-3dab96693fab'; + + const response = await supertest + .post(`${PUBLIC_API_PATH}/${id}`) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({ + attributes: { + title, + }, + }); + + expect(response.status).to.be(409); + expect(response.body.message).to.be( + 'A dashboard with saved object ID be3733a0-9efe-11e7-acb3-3dab96693fab already exists.' + ); + }); + }); +} diff --git a/test/api_integration/apis/dashboards/create_dashboard/validation.ts b/test/api_integration/apis/dashboards/create_dashboard/validation.ts new file mode 100644 index 000000000000..c7f0917a7180 --- /dev/null +++ b/test/api_integration/apis/dashboards/create_dashboard/validation.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", 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 { PUBLIC_API_PATH } from '@kbn/dashboard-plugin/server'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + describe('validation', () => { + it('returns error when attributes object is not provided', async () => { + const response = await supertest + .post(PUBLIC_API_PATH) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({}); + expect(response.status).to.be(400); + expect(response.body.statusCode).to.be(400); + expect(response.body.message).to.be( + '[request body.attributes.title]: expected value of type [string] but got [undefined]' + ); + }); + + it('returns error when title is not provided', async () => { + const response = await supertest + .post(PUBLIC_API_PATH) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({ + attributes: {}, + }); + expect(response.status).to.be(400); + expect(response.body.statusCode).to.be(400); + expect(response.body.message).to.be( + '[request body.attributes.title]: expected value of type [string] but got [undefined]' + ); + }); + + it('returns error if panels is not an array', async () => { + const response = await supertest + .post(PUBLIC_API_PATH) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({ + attributes: { + title: 'foo', + panels: {}, + }, + }); + expect(response.status).to.be(400); + expect(response.body.statusCode).to.be(400); + expect(response.body.message).to.be( + '[request body.attributes.panels]: expected value of type [array] but got [Object]' + ); + }); + }); +} diff --git a/test/api_integration/apis/dashboards/delete_dashboard/index.ts b/test/api_integration/apis/dashboards/delete_dashboard/index.ts new file mode 100644 index 000000000000..41494dfd986d --- /dev/null +++ b/test/api_integration/apis/dashboards/delete_dashboard/index.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 kibanaServer = getService('kibanaServer'); + describe('dashboards - delete', () => { + before(async () => { + await kibanaServer.importExport.load( + 'test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.unload( + 'test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + }); + loadTestFile(require.resolve('./main')); + }); +} diff --git a/test/api_integration/apis/dashboards/delete_dashboard/main.ts b/test/api_integration/apis/dashboards/delete_dashboard/main.ts new file mode 100644 index 000000000000..19ed2b2e1c05 --- /dev/null +++ b/test/api_integration/apis/dashboards/delete_dashboard/main.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", 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 { PUBLIC_API_PATH } from '@kbn/dashboard-plugin/server'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + describe('main', () => { + it('should return 404 for a non-existent dashboard', async () => { + const response = await supertest + .delete(`${PUBLIC_API_PATH}/non-existent-dashboard`) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send(); + + expect(response.status).to.be(404); + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'A dashboard with saved object ID non-existent-dashboard was not found.', + }); + }); + + it('should return 200 if the dashboard is deleted', async () => { + const response = await supertest + .delete(`${PUBLIC_API_PATH}/be3733a0-9efe-11e7-acb3-3dab96693fab`) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send(); + + expect(response.status).to.be(200); + }); + }); +} diff --git a/test/api_integration/apis/dashboards/get_dashboard/index.ts b/test/api_integration/apis/dashboards/get_dashboard/index.ts new file mode 100644 index 000000000000..82ac6f1903cb --- /dev/null +++ b/test/api_integration/apis/dashboards/get_dashboard/index.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 kibanaServer = getService('kibanaServer'); + describe('dashboards - get', () => { + before(async () => { + await kibanaServer.importExport.load( + 'test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.unload( + 'test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + }); + loadTestFile(require.resolve('./main')); + }); +} diff --git a/test/api_integration/apis/dashboards/get_dashboard/main.ts b/test/api_integration/apis/dashboards/get_dashboard/main.ts new file mode 100644 index 000000000000..b6585c0c4f48 --- /dev/null +++ b/test/api_integration/apis/dashboards/get_dashboard/main.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", 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 { PUBLIC_API_PATH } from '@kbn/dashboard-plugin/server'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + describe('main', () => { + it('should return 200 with an existing dashboard', async () => { + const response = await supertest + .get(`${PUBLIC_API_PATH}/be3733a0-9efe-11e7-acb3-3dab96693fab`) + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send(); + + expect(response.status).to.be(200); + + expect(response.body.item.id).to.be('be3733a0-9efe-11e7-acb3-3dab96693fab'); + expect(response.body.item.type).to.be('dashboard'); + expect(response.body.item.attributes.title).to.be('Requests'); + + // Does not return unsupported options from the saved object + expect(response.body.item.attributes.options).to.not.have.keys(['darkTheme']); + expect(response.body.item.attributes.refreshInterval).to.not.have.keys(['display']); + }); + }); +} diff --git a/test/api_integration/apis/dashboards/index.ts b/test/api_integration/apis/dashboards/index.ts new file mode 100644 index 000000000000..f844c0216892 --- /dev/null +++ b/test/api_integration/apis/dashboards/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", 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 ({ loadTestFile }: FtrProviderContext) { + describe('dashboards', () => { + loadTestFile(require.resolve('./create_dashboard')); + loadTestFile(require.resolve('./delete_dashboard')); + loadTestFile(require.resolve('./get_dashboard')); + loadTestFile(require.resolve('./update_dashboard')); + loadTestFile(require.resolve('./list_dashboards')); + }); +} diff --git a/test/api_integration/apis/dashboards/list_dashboards/index.ts b/test/api_integration/apis/dashboards/list_dashboards/index.ts new file mode 100644 index 000000000000..10f77ad3fee5 --- /dev/null +++ b/test/api_integration/apis/dashboards/list_dashboards/index.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 kibanaServer = getService('kibanaServer'); + const supertest = getService('supertest'); + describe('dashboards - list', () => { + const createManyDashboards = async (count: number) => { + const fileChunks: string[] = []; + for (let i = 0; i < count; i++) { + const id = `test-dashboard-${i}`; + fileChunks.push( + JSON.stringify({ + type: 'dashboard', + id, + attributes: { + title: `My dashboard (${i})`, + kibanaSavedObjectMeta: { searchSourceJSON: '{}' }, + }, + references: [], + }) + ); + } + + await supertest + .post(`/api/saved_objects/_import`) + .attach('file', Buffer.from(fileChunks.join('\n'), 'utf8'), 'export.ndjson') + .expect(200); + }; + before(async () => { + await createManyDashboards(100); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + }); + loadTestFile(require.resolve('./main')); + }); +} diff --git a/test/api_integration/apis/dashboards/list_dashboards/main.ts b/test/api_integration/apis/dashboards/list_dashboards/main.ts new file mode 100644 index 000000000000..c0ef1059169e --- /dev/null +++ b/test/api_integration/apis/dashboards/list_dashboards/main.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", 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 { PUBLIC_API_PATH } from '@kbn/dashboard-plugin/server'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + describe('main', () => { + it('should retrieve a paginated list of dashboards', async () => { + const response = await supertest + .get(`${PUBLIC_API_PATH}`) + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send(); + + expect(response.status).to.be(200); + expect(response.body.total).to.be(100); + expect(response.body.items[0].id).to.be('test-dashboard-0'); + expect(response.body.items.length).to.be(20); + }); + + it('should allow users to set a per page limit', async () => { + const response = await supertest + .get(`${PUBLIC_API_PATH}?perPage=10`) + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send(); + + expect(response.status).to.be(200); + expect(response.body.total).to.be(100); + expect(response.body.items.length).to.be(10); + }); + + it('should allow users to paginate through the list of dashboards', async () => { + const response = await supertest + .get(`${PUBLIC_API_PATH}?page=5&perPage=10`) + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send(); + + expect(response.status).to.be(200); + expect(response.body.total).to.be(100); + expect(response.body.items.length).to.be(10); + expect(response.body.items[0].id).to.be('test-dashboard-40'); + }); + }); +} diff --git a/test/api_integration/apis/dashboards/update_dashboard/index.ts b/test/api_integration/apis/dashboards/update_dashboard/index.ts new file mode 100644 index 000000000000..c2a8d7d16cb2 --- /dev/null +++ b/test/api_integration/apis/dashboards/update_dashboard/index.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 kibanaServer = getService('kibanaServer'); + describe('dashboards - update', () => { + before(async () => { + await kibanaServer.importExport.load( + 'test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + }); + + after(async () => { + await kibanaServer.importExport.unload( + 'test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + }); + loadTestFile(require.resolve('./main')); + loadTestFile(require.resolve('./validation')); + }); +} diff --git a/test/api_integration/apis/dashboards/update_dashboard/main.ts b/test/api_integration/apis/dashboards/update_dashboard/main.ts new file mode 100644 index 000000000000..18a7d5ca2d3f --- /dev/null +++ b/test/api_integration/apis/dashboards/update_dashboard/main.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", 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 { PUBLIC_API_PATH } from '@kbn/dashboard-plugin/server'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + describe('main', () => { + it('should return 201 with an updated dashboard', async () => { + const response = await supertest + .put(`${PUBLIC_API_PATH}/be3733a0-9efe-11e7-acb3-3dab96693fab`) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({ + attributes: { + title: 'Refresh Requests (Updated)', + options: { useMargins: false }, + panels: [ + { + type: 'visualization', + gridData: { x: 0, y: 0, w: 48, h: 60, i: '1' }, + panelIndex: '1', + panelRefName: 'panel_1', + version: '7.3.0', + }, + ], + timeFrom: 'Wed Sep 16 2015 22:52:17 GMT-0700', + timeRestore: true, + timeTo: 'Fri Sep 18 2015 12:24:38 GMT-0700', + }, + references: [ + { + id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab', + name: '1:panel_1', + type: 'visualization', + }, + ], + }); + + expect(response.status).to.be(201); + + expect(response.body.item.id).to.be('be3733a0-9efe-11e7-acb3-3dab96693fab'); + expect(response.body.item.type).to.be('dashboard'); + expect(response.body.item.attributes.title).to.be('Refresh Requests (Updated)'); + }); + + it('should return 404 when updating a non-existent dashboard', async () => { + const response = await supertest + .put(`${PUBLIC_API_PATH}/not-an-id`) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({ + attributes: { + title: 'Some other dashboard (updated)', + }, + }); + + expect(response.status).to.be(404); + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'A dashboard with saved object ID not-an-id was not found.', + }); + }); + }); +} diff --git a/test/api_integration/apis/dashboards/update_dashboard/validation.ts b/test/api_integration/apis/dashboards/update_dashboard/validation.ts new file mode 100644 index 000000000000..4a7a069e2461 --- /dev/null +++ b/test/api_integration/apis/dashboards/update_dashboard/validation.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", 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 { PUBLIC_API_PATH } from '@kbn/dashboard-plugin/server'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + describe('validation', () => { + it('returns error when attributes object is not provided', async () => { + const response = await supertest + .put(`${PUBLIC_API_PATH}/be3733a0-9efe-11e7-acb3-3dab96693fab`) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({}); + expect(response.status).to.be(400); + expect(response.body.statusCode).to.be(400); + expect(response.body.message).to.be( + '[request body.attributes.title]: expected value of type [string] but got [undefined]' + ); + }); + + it('returns error when title is not provided', async () => { + const response = await supertest + .put(`${PUBLIC_API_PATH}/be3733a0-9efe-11e7-acb3-3dab96693fab`) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({ + attributes: {}, + }); + expect(response.status).to.be(400); + expect(response.body.statusCode).to.be(400); + expect(response.body.message).to.be( + '[request body.attributes.title]: expected value of type [string] but got [undefined]' + ); + }); + + it('returns error if panels is not an array', async () => { + const response = await supertest + .put(`${PUBLIC_API_PATH}/be3733a0-9efe-11e7-acb3-3dab96693fab`) + .set('kbn-xsrf', 'true') + .set('ELASTIC_HTTP_VERSION_HEADER', '2023-10-31') + .send({ + attributes: { + title: 'foo', + panels: {}, + }, + }); + expect(response.status).to.be(400); + expect(response.body.statusCode).to.be(400); + expect(response.body.message).to.be( + '[request body.attributes.panels]: expected value of type [array] but got [Object]' + ); + }); + }); +} diff --git a/test/api_integration/apis/data_views/fields_for_wildcard_route/response.ts b/test/api_integration/apis/data_views/fields_for_wildcard_route/response.ts index 2b0fa0dab442..a80ca89ee486 100644 --- a/test/api_integration/apis/data_views/fields_for_wildcard_route/response.ts +++ b/test/api_integration/apis/data_views/fields_for_wildcard_route/response.ts @@ -80,7 +80,8 @@ export default function ({ getService }: FtrProviderContext) { }, ]; - describe('fields_for_wildcard_route response', () => { + // Failing: See https://github.com/elastic/kibana/issues/199413 + describe.skip('fields_for_wildcard_route response', () => { before(() => esArchiver.load('test/api_integration/fixtures/es_archiver/index_patterns/basic_index') ); diff --git a/test/api_integration/apis/index.ts b/test/api_integration/apis/index.ts index bbd7c3abf864..af1cbf2464fa 100644 --- a/test/api_integration/apis/index.ts +++ b/test/api_integration/apis/index.ts @@ -14,6 +14,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./console')); loadTestFile(require.resolve('./core')); loadTestFile(require.resolve('./custom_integration')); + loadTestFile(require.resolve('./dashboards')); loadTestFile(require.resolve('./general')); loadTestFile(require.resolve('./home')); loadTestFile(require.resolve('./data_view_field_editor')); diff --git a/test/common/plugins/otel_metrics/kibana.jsonc b/test/common/plugins/otel_metrics/kibana.jsonc index e64546f44605..dea9f97260c7 100644 --- a/test/common/plugins/otel_metrics/kibana.jsonc +++ b/test/common/plugins/otel_metrics/kibana.jsonc @@ -2,6 +2,8 @@ "type": "plugin", "id": "@kbn/open-telemetry-instrumented-plugin", "owner": "@elastic/obs-ux-infra_services-team", + "group": "platform", + "visibility": "shared", "plugin": { "id": "openTelemetryInstrumentedPlugin", "server": true, diff --git a/test/common/services/index.ts b/test/common/services/index.ts index a2b80c01a18b..c3fcdda2cf93 100644 --- a/test/common/services/index.ts +++ b/test/common/services/index.ts @@ -21,7 +21,7 @@ const { esDeleteAllIndices, savedObjectInfo, indexPatterns, - bsearch, + search, console, supertest, esSupertest, @@ -42,7 +42,7 @@ export const services = { esDeleteAllIndices, savedObjectInfo, indexPatterns, - bsearch, + search, console, supertest, esSupertest, diff --git a/test/functional/apps/console/_autocomplete.ts b/test/functional/apps/console/_autocomplete.ts index 99e97d979d28..451e54613559 100644 --- a/test/functional/apps/console/_autocomplete.ts +++ b/test/functional/apps/console/_autocomplete.ts @@ -351,7 +351,8 @@ GET _search }); }); - describe('index fields autocomplete', () => { + // FLAKY: https://github.com/elastic/kibana/issues/198109 + describe.skip('index fields autocomplete', () => { const indexName = `index_field_test-${Date.now()}-${Math.random()}`; before(async () => { diff --git a/test/functional/apps/dashboard/group1/edit_visualizations.js b/test/functional/apps/dashboard/group1/edit_visualizations.js index f065748f09b0..9e91ed1ea112 100644 --- a/test/functional/apps/dashboard/group1/edit_visualizations.js +++ b/test/functional/apps/dashboard/group1/edit_visualizations.js @@ -10,7 +10,7 @@ import expect from '@kbn/expect'; export default function ({ getService, getPageObjects }) { - const { dashboard, header, visualize, common, visEditor } = getPageObjects([ + const { dashboard, header, visualize, visEditor } = getPageObjects([ 'dashboard', 'header', 'visualize', @@ -114,7 +114,6 @@ export default function ({ getService, getPageObjects }) { await header.waitUntilLoadingHasFinished(); await appsMenu.clickLink('Visualize Library'); - await common.clickConfirmOnModal(); expect(await testSubjects.exists('visualizationLandingPage')).to.be(true); }); @@ -132,7 +131,6 @@ export default function ({ getService, getPageObjects }) { await header.waitUntilLoadingHasFinished(); await appsMenu.clickLink('Visualize Library'); - await common.clickConfirmOnModal(); expect(await testSubjects.exists('visualizationLandingPage')).to.be(true); }); diff --git a/test/functional/apps/dashboard/group3/dashboard_state.ts b/test/functional/apps/dashboard/group3/dashboard_state.ts index 40022c155f45..9822c2ce361a 100644 --- a/test/functional/apps/dashboard/group3/dashboard_state.ts +++ b/test/functional/apps/dashboard/group3/dashboard_state.ts @@ -309,12 +309,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { panels: (appState.panels ?? []).map((panel) => { return { ...panel, - embeddableConfig: { - ...(panel.embeddableConfig ?? {}), + panelConfig: { + ...(panel.panelConfig ?? {}), vis: { - ...((panel.embeddableConfig?.vis as object) ?? {}), + ...((panel.panelConfig?.vis as object) ?? {}), colors: { - ...((panel.embeddableConfig?.vis as { colors: object })?.colors ?? {}), + ...((panel.panelConfig?.vis as { colors: object })?.colors ?? {}), ['80000']: 'FFFFFF', }, }, @@ -353,10 +353,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { panels: (appState.panels ?? []).map((panel) => { return { ...panel, - embeddableConfig: { - ...(panel.embeddableConfig ?? {}), + panelConfig: { + ...(panel.panelConfig ?? {}), vis: { - ...((panel.embeddableConfig?.vis as object) ?? {}), + ...((panel.panelConfig?.vis as object) ?? {}), colors: {}, }, }, diff --git a/test/functional/apps/discover/esql/_esql_view.ts b/test/functional/apps/discover/esql/_esql_view.ts index 272de320d205..18841d07dac3 100644 --- a/test/functional/apps/discover/esql/_esql_view.ts +++ b/test/functional/apps/discover/esql/_esql_view.ts @@ -843,6 +843,23 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const list = await discover.getHistogramLegendList(); expect(list).to.eql(['css', 'gif', 'jpg', 'php', 'png']); }); + + it('should choose breakdown field when selected from field stats', async () => { + await discover.selectTextBaseLang(); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + + const testQuery = 'from logstash-*'; + await monacoEditor.setCodeEditorValue(testQuery); + await testSubjects.click('querySubmitButton'); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + + await unifiedFieldList.clickFieldListAddBreakdownField('extension'); + await header.waitUntilLoadingHasFinished(); + const list = await discover.getHistogramLegendList(); + expect(list).to.eql(['css', 'gif', 'jpg', 'php', 'png']); + }); }); }); } diff --git a/test/functional/apps/discover/group1/_discover_histogram_breakdown.ts b/test/functional/apps/discover/group1/_discover_histogram_breakdown.ts index 5ce8732e5355..6f04a6df1b6b 100644 --- a/test/functional/apps/discover/group1/_discover_histogram_breakdown.ts +++ b/test/functional/apps/discover/group1/_discover_histogram_breakdown.ts @@ -14,11 +14,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); const filterBar = getService('filterBar'); - const { common, discover, header, timePicker } = getPageObjects([ + const { common, discover, header, timePicker, unifiedFieldList } = getPageObjects([ 'common', 'discover', 'header', 'timePicker', + 'unifiedFieldList', ]); describe('discover unified histogram breakdown', function describeIndexTests() { @@ -36,6 +37,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); }); + it('should apply breakdown when selected from field stats', async () => { + await unifiedFieldList.clickFieldListAddBreakdownField('geo.dest'); + await header.waitUntilLoadingHasFinished(); + const list = await discover.getHistogramLegendList(); + expect(list).to.eql(['CN', 'IN', 'US', 'Other']); + }); + it('should choose breakdown field', async () => { await discover.chooseBreakdownField('extension.raw'); await header.waitUntilLoadingHasFinished(); diff --git a/test/functional/apps/discover/group3/_lens_vis.ts b/test/functional/apps/discover/group3/_lens_vis.ts index 0864382cad7a..03641ee5bcb4 100644 --- a/test/functional/apps/discover/group3/_lens_vis.ts +++ b/test/functional/apps/discover/group3/_lens_vis.ts @@ -110,7 +110,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { return seriesType; } - describe('discover lens vis', function () { + // FLAKY: https://github.com/elastic/kibana/issues/184600 + describe.skip('discover lens vis', function () { before(async () => { await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); diff --git a/test/functional/apps/discover/group6/_sidebar_field_stats.ts b/test/functional/apps/discover/group6/_sidebar_field_stats.ts index 325adb313ed6..e72560660999 100644 --- a/test/functional/apps/discover/group6/_sidebar_field_stats.ts +++ b/test/functional/apps/discover/group6/_sidebar_field_stats.ts @@ -155,77 +155,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedFieldList.waitUntilSidebarHasLoaded(); }); - it('should show top values popover for numeric field', async () => { + it('should not show top values popover for numeric field', async () => { await unifiedFieldList.clickFieldListItem('bytes'); - await testSubjects.existOrFail('dscFieldStats-topValues'); - expect(await testSubjects.getVisibleText('dscFieldStats-title')).to.be('Top values'); - const topValuesRows = await testSubjects.findAll('dscFieldStats-topValues-bucket'); - expect(topValuesRows.length).to.eql(10); - expect(await testSubjects.getVisibleText('dscFieldStats-statsFooter')).to.contain( - '42 sample values' - ); - - await unifiedFieldList.clickFieldListPlusFilter('bytes', '0'); - const editorValue = await monacoEditor.getCodeEditorValue(); - expect(editorValue).to.eql( - `from logstash-* METADATA _index, _id | sort @timestamp desc | limit 500\n| WHERE \`bytes\`==0` - ); + await testSubjects.missingOrFail('dscFieldStats-statsFooter'); await unifiedFieldList.closeFieldPopover(); }); - it('should show a top values popover for a keyword field', async () => { + it('should not show a top values popover for a keyword field', async () => { await unifiedFieldList.clickFieldListItem('extension.raw'); - await testSubjects.existOrFail('dscFieldStats-topValues'); - expect(await testSubjects.getVisibleText('dscFieldStats-title')).to.be('Top values'); - const topValuesRows = await testSubjects.findAll('dscFieldStats-topValues-bucket'); - expect(topValuesRows.length).to.eql(5); - await testSubjects.missingOrFail('unifiedFieldStats-buttonGroup'); - await testSubjects.missingOrFail('unifiedFieldStats-histogram'); - expect(await testSubjects.getVisibleText('dscFieldStats-statsFooter')).to.contain( - '500 sample values' - ); - - await unifiedFieldList.clickFieldListPlusFilter('extension.raw', 'css'); - const editorValue = await monacoEditor.getCodeEditorValue(); - expect(editorValue).to.eql( - `from logstash-* METADATA _index, _id | sort @timestamp desc | limit 500\n| WHERE \`extension.raw\`=="css"` - ); - - await unifiedFieldList.closeFieldPopover(); - }); - - it('should show a top values popover for an ip field', async () => { - await unifiedFieldList.clickFieldListItem('clientip'); - await testSubjects.existOrFail('dscFieldStats-topValues'); - expect(await testSubjects.getVisibleText('dscFieldStats-title')).to.be('Top values'); - const topValuesRows = await testSubjects.findAll('dscFieldStats-topValues-bucket'); - expect(topValuesRows.length).to.eql(10); - await testSubjects.missingOrFail('unifiedFieldStats-buttonGroup'); - await testSubjects.missingOrFail('unifiedFieldStats-histogram'); - expect(await testSubjects.getVisibleText('dscFieldStats-statsFooter')).to.contain( - '32 sample values' - ); - - await unifiedFieldList.clickFieldListPlusFilter('clientip', '216.126.255.31'); - const editorValue = await monacoEditor.getCodeEditorValue(); - expect(editorValue).to.eql( - `from logstash-* METADATA _index, _id | sort @timestamp desc | limit 500\n| WHERE \`clientip\`::string=="216.126.255.31"` - ); - - await unifiedFieldList.closeFieldPopover(); - }); - - it('should show a top values popover for _index field', async () => { - await unifiedFieldList.clickFieldListItem('_index'); - await testSubjects.existOrFail('dscFieldStats-topValues'); - expect(await testSubjects.getVisibleText('dscFieldStats-title')).to.be('Top values'); - const topValuesRows = await testSubjects.findAll('dscFieldStats-topValues-bucket'); - expect(topValuesRows.length).to.eql(1); - await testSubjects.missingOrFail('unifiedFieldStats-buttonGroup'); - await testSubjects.missingOrFail('unifiedFieldStats-histogram'); - expect(await testSubjects.getVisibleText('dscFieldStats-statsFooter')).to.contain( - '500 sample values' - ); + await testSubjects.missingOrFail('dscFieldStats-statsFooter'); await unifiedFieldList.closeFieldPopover(); }); @@ -240,102 +178,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedFieldList.closeFieldPopover(); }); - it('should show examples for geo points field', async () => { - await unifiedFieldList.clickFieldListItem('geo.coordinates'); - await testSubjects.existOrFail('dscFieldStats-topValues'); - expect(await testSubjects.getVisibleText('dscFieldStats-title')).to.be('Examples'); - const topValuesRows = await testSubjects.findAll('dscFieldStats-topValues-bucket'); - expect(topValuesRows.length).to.eql(11); - await testSubjects.missingOrFail('unifiedFieldStats-buttonGroup'); - await testSubjects.missingOrFail('unifiedFieldStats-histogram'); - expect(await testSubjects.getVisibleText('dscFieldStats-statsFooter')).to.contain( - '100 sample records' - ); - await unifiedFieldList.closeFieldPopover(); - }); - - it('should show examples for text field', async () => { + it('should not show examples for text field', async () => { await unifiedFieldList.clickFieldListItem('extension'); - await testSubjects.existOrFail('dscFieldStats-topValues'); - expect(await testSubjects.getVisibleText('dscFieldStats-title')).to.be('Examples'); - const topValuesRows = await testSubjects.findAll('dscFieldStats-topValues-bucket'); - expect(topValuesRows.length).to.eql(5); - await testSubjects.missingOrFail('unifiedFieldStats-buttonGroup'); - await testSubjects.missingOrFail('unifiedFieldStats-histogram'); - expect(await testSubjects.getVisibleText('dscFieldStats-statsFooter')).to.contain( - '100 sample records' - ); - - await unifiedFieldList.clickFieldListPlusFilter('extension', 'css'); - const editorValue = await monacoEditor.getCodeEditorValue(); - expect(editorValue).to.eql( - `from logstash-* METADATA _index, _id | sort @timestamp desc | limit 500\n| WHERE \`extension\`=="css"` - ); - - await unifiedFieldList.closeFieldPopover(); - }); - - it('should show examples for _id field', async () => { - await unifiedFieldList.clickFieldListItem('_id'); - await testSubjects.existOrFail('dscFieldStats-topValues'); - expect(await testSubjects.getVisibleText('dscFieldStats-title')).to.be('Examples'); - const topValuesRows = await testSubjects.findAll('dscFieldStats-topValues-bucket'); - expect(topValuesRows.length).to.eql(11); - await testSubjects.missingOrFail('unifiedFieldStats-buttonGroup'); - await testSubjects.missingOrFail('unifiedFieldStats-histogram'); - expect(await testSubjects.getVisibleText('dscFieldStats-statsFooter')).to.contain( - '100 sample records' - ); - await unifiedFieldList.closeFieldPopover(); - }); - - it('should show a top values popover for a more complex query', async () => { - const testQuery = `from logstash-* | sort @timestamp desc | limit 50 | stats avg(bytes) by geo.dest | limit 3`; - await monacoEditor.setCodeEditorValue(testQuery); - await testSubjects.click('querySubmitButton'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - await unifiedFieldList.clickFieldListItem('avg(bytes)'); - await testSubjects.existOrFail('dscFieldStats-topValues'); - expect(await testSubjects.getVisibleText('dscFieldStats-title')).to.be('Top values'); - const topValuesRows = await testSubjects.findAll('dscFieldStats-topValues-bucket'); - expect(topValuesRows.length).to.eql(3); - expect(await testSubjects.getVisibleText('dscFieldStats-statsFooter')).to.contain( - '3 sample values' - ); - - await unifiedFieldList.clickFieldListPlusFilter('avg(bytes)', '5453'); - const editorValue = await monacoEditor.getCodeEditorValue(); - expect(editorValue).to.eql( - `from logstash-* | sort @timestamp desc | limit 50 | stats avg(bytes) by geo.dest | limit 3\n| WHERE \`avg(bytes)\`==5453` - ); - - await unifiedFieldList.closeFieldPopover(); - }); - - it('should show a top values popover for a boolean field', async () => { - const testQuery = `row enabled = true`; - await monacoEditor.setCodeEditorValue(testQuery); - await testSubjects.click('querySubmitButton'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - await unifiedFieldList.clickFieldListItem('enabled'); - await testSubjects.existOrFail('dscFieldStats-topValues'); - expect(await testSubjects.getVisibleText('dscFieldStats-title')).to.be('Top values'); - const topValuesRows = await testSubjects.findAll('dscFieldStats-topValues-bucket'); - expect(topValuesRows.length).to.eql(1); - expect(await unifiedFieldList.getFieldStatsTopValueBucketsVisibleText()).to.be( - 'true\n100%' - ); - expect(await testSubjects.getVisibleText('dscFieldStats-statsFooter')).to.contain( - '1 sample value' - ); - - await unifiedFieldList.clickFieldListMinusFilter('enabled', 'true'); - const editorValue = await monacoEditor.getCodeEditorValue(); - expect(editorValue).to.eql(`row enabled = true\n| WHERE \`enabled\`!=true`); + await testSubjects.missingOrFail('dscFieldStats-statsFooter'); await unifiedFieldList.closeFieldPopover(); }); }); diff --git a/test/functional/apps/getting_started/_shakespeare.ts b/test/functional/apps/getting_started/_shakespeare.ts index d0843fb16d04..e7b88cd069dd 100644 --- a/test/functional/apps/getting_started/_shakespeare.ts +++ b/test/functional/apps/getting_started/_shakespeare.ts @@ -81,7 +81,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // Remove refresh click when vislib is removed // https://github.com/elastic/kibana/issues/56143 - await PageObjects.visualize.clickRefresh(true); + await PageObjects.visualize.clickRefresh(); const expectedChartValues = [111396]; await retry.try(async () => { diff --git a/test/functional/apps/visualize/group2/_gauge_chart.ts b/test/functional/apps/visualize/group2/_gauge_chart.ts index 8ff6d3122908..0f4002efce65 100644 --- a/test/functional/apps/visualize/group2/_gauge_chart.ts +++ b/test/functional/apps/visualize/group2/_gauge_chart.ts @@ -62,7 +62,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.click('gaugePercentageMode'); await testSubjects.setValue('gaugePercentageModeFormatPattern', '0.0%'); await visChart.waitForVisualizationRenderingStabilized(); - await visEditor.clickGo(false); + await visEditor.clickGo(true); await retry.try(async function tryingForTime() { const expectedTexts = ['57.3%', 'Average bytes']; @@ -82,7 +82,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectField('machine.os.raw'); log.debug('Size = 4'); await visEditor.setSize(4); - await visEditor.clickGo(false); + await visEditor.clickGo(true); }); it('should show Split Gauges', async () => { @@ -118,7 +118,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.clickBucket('Metric', 'metrics'); await visEditor.selectAggregation('Min', 'metrics'); await visEditor.selectField('bytes', 'metrics'); - await visEditor.clickGo(false); + await visEditor.clickGo(true); await retry.try(async function tryingForTime() { const metricValue = await visChart.getGaugeValue(); diff --git a/test/functional/apps/visualize/group2/_heatmap_chart.ts b/test/functional/apps/visualize/group2/_heatmap_chart.ts index a8944f1131d0..a3f03eababdd 100644 --- a/test/functional/apps/visualize/group2/_heatmap_chart.ts +++ b/test/functional/apps/visualize/group2/_heatmap_chart.ts @@ -29,7 +29,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { isNewChartsLibraryEnabled = await visChart.isNewChartsLibraryEnabled( 'visualization:visualize:legacyHeatmapChartsLibrary' ); - await visualize.initTests(isNewChartsLibraryEnabled); + await visualize.initTests(!isNewChartsLibraryEnabled); log.debug('navigateToApp visualize'); await visualize.navigateToNewAggBasedVisualization(); log.debug('clickHeatmapChart'); @@ -43,7 +43,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { log.debug('Field = @timestamp'); await visEditor.selectField('@timestamp'); // leaving Interval set to Auto - await visEditor.clickGo(isNewChartsLibraryEnabled); + await visEditor.clickGo(!isNewChartsLibraryEnabled); }); it('should save and load', async function () { @@ -102,7 +102,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show 6 color ranges if changed on options', async function () { await visEditor.clickOptionsTab(); await visEditor.changeHeatmapColorNumbers(6); - await visEditor.clickGo(isNewChartsLibraryEnabled); + await visEditor.clickGo(!isNewChartsLibraryEnabled); await visChart.waitForVisualizationRenderingStabilized(); const legends = await visChart.getLegendEntries(); @@ -143,7 +143,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { log.debug('customize 2 last ranges'); await visEditor.setCustomRangeByIndex(6, '650', '720'); await visEditor.setCustomRangeByIndex(7, '800', '905'); - await visEditor.clickGo(isNewChartsLibraryEnabled); + await visEditor.clickGo(!isNewChartsLibraryEnabled); await visChart.waitForVisualizationRenderingStabilized(); const legends = await visChart.getLegendEntries(); diff --git a/test/functional/apps/visualize/group3/_pie_chart.ts b/test/functional/apps/visualize/group3/_pie_chart.ts index d42d6e72f232..f28ed5c575f1 100644 --- a/test/functional/apps/visualize/group3/_pie_chart.ts +++ b/test/functional/apps/visualize/group3/_pie_chart.ts @@ -28,11 +28,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('pie chart', function () { // Used to track flag before and after reset - let isNewChartsLibraryEnabled = false; const vizName1 = 'Visualization PieChart'; before(async function () { - isNewChartsLibraryEnabled = await visChart.isNewChartsLibraryEnabled(); - await visualize.initTests(isNewChartsLibraryEnabled); + await visualize.initTests(); log.debug('navigateToApp visualize'); await visualize.navigateToNewAggBasedVisualization(); @@ -51,7 +49,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { log.debug('setNumericInterval 4000'); await visEditor.setInterval('40000', { type: 'numeric' }); log.debug('clickGo'); - await visEditor.clickGo(isNewChartsLibraryEnabled); + await visEditor.clickGo(); }); after(async () => { @@ -70,7 +68,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should show 10 slices in pie chart', async function () { - await pieChart.expectPieSliceCount(10, isNewChartsLibraryEnabled); + await pieChart.expectPieSliceCount(10); }); it('should show correct data', async function () { @@ -109,8 +107,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.toggleOtherBucket(2); await visEditor.toggleMissingBucket(2); log.debug('clickGo'); - await visEditor.clickGo(isNewChartsLibraryEnabled); - await pieChart.expectPieChartLabels(expectedTableData, isNewChartsLibraryEnabled); + await visEditor.clickGo(); + await pieChart.expectPieChartLabels(expectedTableData); }); it('should apply correct filter on other bucket', async () => { @@ -118,7 +116,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await pieChart.filterOnPieSlice('Other'); await visChart.waitForVisualization(); - await pieChart.expectPieChartLabels(expectedTableData, isNewChartsLibraryEnabled); + await pieChart.expectPieChartLabels(expectedTableData); await filterBar.removeFilter('machine.os.raw'); await visChart.waitForVisualization(); }); @@ -128,7 +126,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visChart.filterLegend('Other'); await visChart.waitForVisualization(); - await pieChart.expectPieChartLabels(expectedTableData, isNewChartsLibraryEnabled); + await pieChart.expectPieChartLabels(expectedTableData); await filterBar.removeFilter('machine.os.raw'); await visChart.waitForVisualization(); }); @@ -187,8 +185,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.toggleOtherBucket(3); await visEditor.toggleMissingBucket(3); log.debug('clickGo'); - await visEditor.clickGo(isNewChartsLibraryEnabled); - await pieChart.expectPieChartLabels(expectedTableData, isNewChartsLibraryEnabled); + await visEditor.clickGo(); + await pieChart.expectPieChartLabels(expectedTableData); }); }); @@ -205,9 +203,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectAggregation('Terms'); await visEditor.selectField('machine.os.raw'); await visEditor.toggleDisabledAgg(2); - await visEditor.clickGo(isNewChartsLibraryEnabled); + await visEditor.clickGo(); - await pieChart.expectPieChartLabels(expectedTableData, isNewChartsLibraryEnabled); + await pieChart.expectPieChartLabels(expectedTableData); }); it('should correctly save disabled agg', async () => { @@ -217,12 +215,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visChart.waitForRenderingCount(); const expectedTableData = ['ios', 'osx', 'win 7', 'win 8', 'win xp']; - await pieChart.expectPieChartLabels(expectedTableData, isNewChartsLibraryEnabled); + await pieChart.expectPieChartLabels(expectedTableData); }); it('should show correct result when agg is re-enabled', async () => { await visEditor.toggleDisabledAgg(2); - await visEditor.clickGo(isNewChartsLibraryEnabled); + await visEditor.clickGo(); const expectedTableData = [ '0', @@ -287,7 +285,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'osx', ].sort(); - await pieChart.expectPieChartLabels(expectedTableData, isNewChartsLibraryEnabled); + await pieChart.expectPieChartLabels(expectedTableData); }); }); @@ -307,7 +305,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.addNewFilterAggregation(); log.debug('Set the 2nd filter value'); await visEditor.setFilterAggregationValue('geo.dest:"CN"', 1); - await visEditor.clickGo(isNewChartsLibraryEnabled); + await visEditor.clickGo(); const emptyFromTime = 'Sep 19, 2016 @ 06:31:44.000'; const emptyToTime = 'Sep 23, 2016 @ 18:31:44.000'; log.debug( @@ -315,7 +313,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await timePicker.setAbsoluteRange(emptyFromTime, emptyToTime); await visChart.waitForVisualization(); - await visChart.expectError(); }); }); describe('multi series slice', () => { @@ -341,7 +338,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.clickBucket('Split slices'); await visEditor.selectAggregation('Terms'); await visEditor.selectField('geo.dest'); - await visEditor.clickGo(isNewChartsLibraryEnabled); + await visEditor.clickGo(); }); it('should show correct chart', async () => { @@ -398,7 +395,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ['360,000', '47', 'BR', '2'], ].map((row) => // the count of records is not shown for every split level in the new charting library - isNewChartsLibraryEnabled ? [row[0], ...row.slice(2)] : row + [row[0], ...row.slice(2)] ); await inspector.open(); @@ -430,26 +427,22 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { '360,000', 'CN', ].sort(); - if (isNewChartsLibraryEnabled) { - await visEditor.clickOptionsTab(); - await visEditor.togglePieLegend(); - await visEditor.togglePieNestedLegend(); - await visEditor.clickDataTab(); - await visEditor.clickGo(isNewChartsLibraryEnabled); - } + + await visEditor.clickOptionsTab(); + await visEditor.togglePieLegend(); + await visEditor.togglePieNestedLegend(); + await visEditor.clickDataTab(); + await visEditor.clickGo(); + await visChart.filterLegend('CN'); await visChart.waitForVisualization(); - await pieChart.expectPieChartLabels(expectedTableData, isNewChartsLibraryEnabled); + await pieChart.expectPieChartLabels(expectedTableData); await filterBar.removeFilter('geo.dest'); await visChart.waitForVisualization(); }); - it('should still showing pie chart when a subseries have zero data', async function () { - if (isNewChartsLibraryEnabled) { - // TODO: it seems that adding a filter agg which has no results to a pie chart breaks it and instead it shows "no data" - return; - } - + // TODO: it seems that adding a filter agg which has no results to a pie chart breaks it and instead it shows "no data" + it.skip('should still showing pie chart when a subseries have zero data', async function () { await visualize.navigateToNewAggBasedVisualization(); log.debug('clickPieChart'); await visualize.clickPieChart(); @@ -468,7 +461,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectAggregation('Filters'); log.debug('Set the 1st filter value of the aggregation id 3'); await visEditor.setFilterAggregationValue('geo.dest:"UX"', 0, 3); - await visEditor.clickGo(isNewChartsLibraryEnabled); + await visEditor.clickGo(); const legends = await visChart.getLegendEntries(); const expectedLegends = ['geo.dest:"US"', 'geo.dest:"UX"']; expect(legends).to.eql(expectedLegends); @@ -489,7 +482,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.clickBucket('Split slices'); await visEditor.selectAggregation('Terms'); await visEditor.selectField('geo.src'); - await visEditor.clickGo(isNewChartsLibraryEnabled); + await visEditor.clickGo(); }); it('shows correct split chart', async () => { @@ -521,7 +514,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ['osx', '1,322', 'BR', '30'], ].map((row) => // the count of records is not shown for every split level in the new charting library - isNewChartsLibraryEnabled ? [row[0], ...row.slice(2)] : row + [row[0], ...row.slice(2)] ); await inspector.open(); await inspector.setTablePageSize(50); @@ -538,7 +531,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ['osx', '228', 'CN', '228'], ].map((row) => // the count of records is not shown for every split level in the new charting library - isNewChartsLibraryEnabled ? [row[0], ...row.slice(2)] : row + [row[0], ...row.slice(2)] ); await visChart.filterLegend('CN'); await header.waitUntilLoadingHasFinished(); diff --git a/test/functional/apps/visualize/group5/_tsvb_time_series.ts b/test/functional/apps/visualize/group5/_tsvb_time_series.ts index 43f18462f74e..2c2cfe65da1a 100644 --- a/test/functional/apps/visualize/group5/_tsvb_time_series.ts +++ b/test/functional/apps/visualize/group5/_tsvb_time_series.ts @@ -434,7 +434,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { legendNames = await visualBuilder.getLegendNames(); expect(legendNames).to.eql(['png', 'php']); - await visualize.clickRefresh(true); + await visualize.clickRefresh(); legendNames = await visualBuilder.getLegendNames(); expect(legendNames).to.eql(['png', 'php']); }); diff --git a/test/functional/apps/visualize/replaced_vislib_chart_types/_area_chart.ts b/test/functional/apps/visualize/replaced_vislib_chart_types/_area_chart.ts index cbbdd8f9ffdc..4d558b1b7c14 100644 --- a/test/functional/apps/visualize/replaced_vislib_chart_types/_area_chart.ts +++ b/test/functional/apps/visualize/replaced_vislib_chart_types/_area_chart.ts @@ -49,7 +49,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const intervalValue = await visEditor.getInterval(); log.debug('intervalValue = ' + intervalValue); expect(intervalValue[0]).to.be('Auto'); - await visEditor.clickGo(true); + await visEditor.clickGo(); }; describe('area charts', function indexPatternCreation() { @@ -177,7 +177,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.toggleOpenEditor(2); await visEditor.setInterval('Second'); - await visEditor.clickGo(true); + await visEditor.clickGo(); await inspector.open(); await inspector.expectTableData(expectedTableData); await inspector.close(); @@ -209,7 +209,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.toggleAdvancedParams('2'); await visEditor.toggleScaleMetrics(); - await visEditor.clickGo(true); + await visEditor.clickGo(); await inspector.open(); await inspector.expectTableData(expectedTableData); await inspector.close(); @@ -243,7 +243,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectAggregation('Top Hit', 'metrics'); await visEditor.selectField('bytes', 'metrics'); await visEditor.selectAggregateWith('average'); - await visEditor.clickGo(true); + await visEditor.clickGo(); await inspector.open(); await inspector.expectTableData(expectedTableData); await inspector.close(); @@ -277,7 +277,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.clickYAxisOptions(axisId); await visEditor.selectYAxisScaleType(axisId, 'log'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabelsAsNumbers(xyChartSelector); const minLabel = 1; const maxLabel = 900; @@ -289,7 +289,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting log scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabelsAsNumbers(xyChartSelector); const minLabel = 1; const maxLabel = 900; @@ -302,7 +302,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show ticks on selecting square root scale', async () => { await visEditor.selectYAxisScaleType(axisId, 'square root'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '200', '400', '600', '800', '1,000', '1,200', '1,400']; expect(labels).to.eql(expectedLabels); @@ -310,7 +310,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting square root scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '200', '400', '600', '800', '1,000', '1,200', '1,400']; expect(labels).to.eql(expectedLabels); @@ -319,7 +319,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show ticks on selecting linear scale', async () => { await visEditor.selectYAxisScaleType(axisId, 'linear'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); log.debug(labels); const expectedLabels = ['0', '200', '400', '600', '800', '1,000', '1,200', '1,400']; @@ -328,7 +328,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting linear scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '200', '400', '600', '800', '1,000', '1,200', '1,400']; expect(labels).to.eql(expectedLabels); @@ -353,7 +353,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectAggregation('Date Histogram'); await visEditor.selectField('@timestamp'); await visEditor.setInterval('Year'); - await visEditor.clickGo(true); + await visEditor.clickGo(); // This svg area is composed by 7 years (2013 - 2019). // 7 points are used to draw the upper line (usually called y1) // 7 points compose the lower line (usually called y0) @@ -376,7 +376,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectAggregation('Date Histogram'); await visEditor.selectField('@timestamp'); await visEditor.setInterval('Month'); - await visEditor.clickGo(true); + await visEditor.clickGo(); // This svg area is composed by 67 months 3 (2013) + 5 * 12 + 4 (2019) // 67 points are used to draw the upper line (usually called y1) // 67 points compose the lower line (usually called y0) diff --git a/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_chart.ts b/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_chart.ts index a4a74e499c31..1a22825467e1 100644 --- a/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_chart.ts +++ b/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_chart.ts @@ -41,7 +41,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectField('extension.raw'); log.debug('switch from Rows to Columns'); await visEditor.clickSplitDirection('Columns'); - await visEditor.clickGo(true); + await visEditor.clickGo(); }; before(async () => { @@ -96,7 +96,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { log.debug('Order By = Term'); await visEditor.selectOrderByMetric(2, '_key'); - await visEditor.clickGo(true); + await visEditor.clickGo(); await retry.try(async function () { const data = await visChart.getLineChartData(xyChartSelector); log.debug('data=' + data); @@ -181,7 +181,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.clickYAxisOptions(axisId); await visEditor.selectYAxisScaleType(axisId, 'log'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabelsAsNumbers(xyChartSelector); const minLabel = 1; const maxLabel = 7000; @@ -193,7 +193,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting log scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabelsAsNumbers(xyChartSelector); const minLabel = 1; const maxLabel = 7000; @@ -206,7 +206,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show ticks on selecting square root scale', async () => { await visEditor.selectYAxisScaleType(axisId, 'square root'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '2,000', '4,000', '6,000', '8,000']; @@ -215,7 +215,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting square root scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '2,000', '4,000', '6,000', '8,000']; expect(labels).to.eql(expectedLabels); @@ -224,7 +224,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show ticks on selecting linear scale', async () => { await visEditor.selectYAxisScaleType(axisId, 'linear'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); log.debug(labels); const expectedLabels = ['0', '2,000', '4,000', '6,000', '8,000']; @@ -233,7 +233,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting linear scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '2,000', '4,000', '6,000', '8,000']; expect(labels).to.eql(expectedLabels); @@ -262,7 +262,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.clickBucket('X-axis'); log.debug('Aggregation = Date Histogram'); await visEditor.selectAggregation('Date Histogram'); - await visEditor.clickGo(true); + await visEditor.clickGo(); const title = await visChart.getYAxisTitle(xyChartSelector); expect(title).to.be('Serial Diff of Count'); }); @@ -270,7 +270,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should change y-axis label to custom', async () => { log.debug('set custom label of y-axis to "Custom"'); await visEditor.setCustomLabel('Custom', 1); - await visEditor.clickGo(true); + await visEditor.clickGo(); const title = await visChart.getYAxisTitle(xyChartSelector); expect(title).to.be('Custom'); }); @@ -285,7 +285,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should apply with selected bucket', async () => { log.debug('Metrics agg = Average Bucket'); await visEditor.selectAggregation('Average Bucket', 'metrics'); - await visEditor.clickGo(true); + await visEditor.clickGo(); const title = await visChart.getYAxisTitle(xyChartSelector); expect(title).to.be('Overall Average of Count'); }); @@ -293,7 +293,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should change sub metric custom label and calculate y-axis title', async () => { log.debug('set custom label of sub metric to "Cats"'); await visEditor.setCustomLabel('Cats', '1-metric'); - await visEditor.clickGo(true); + await visEditor.clickGo(); const title = await visChart.getYAxisTitle(xyChartSelector); expect(title).to.be('Overall Average of Cats'); }); @@ -301,7 +301,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should outer custom label', async () => { log.debug('set custom label to "Custom"'); await visEditor.setCustomLabel('Custom', 1); - await visEditor.clickGo(true); + await visEditor.clickGo(); const title = await visChart.getYAxisTitle(xyChartSelector); expect(title).to.be('Custom'); }); diff --git a/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_series.ts b/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_series.ts index 3b0ea28b71e4..a8630cec747f 100644 --- a/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_series.ts +++ b/test/functional/apps/visualize/replaced_vislib_chart_types/_line_chart_split_series.ts @@ -39,7 +39,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectAggregation('Terms'); log.debug('Field = extension'); await visEditor.selectField('extension.raw'); - await visEditor.clickGo(true); + await visEditor.clickGo(); }; before(async () => { @@ -94,7 +94,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { log.debug('Order By = Term'); await visEditor.selectOrderByMetric(2, '_key'); - await visEditor.clickGo(true); + await visEditor.clickGo(); await retry.try(async function () { const data = await visChart.getLineChartData(xyChartSelector); log.debug('data=' + data); @@ -180,7 +180,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.clickYAxisOptions(axisId); await visEditor.selectYAxisScaleType(axisId, 'log'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabelsAsNumbers(xyChartSelector); const minLabel = 1; const maxLabel = 900; @@ -192,7 +192,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting log scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabelsAsNumbers(xyChartSelector); const minLabel = 1; const maxLabel = 900; @@ -205,7 +205,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show ticks on selecting square root scale', async () => { await visEditor.selectYAxisScaleType(axisId, 'square root'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '2,000', '4,000', '6,000', '8,000']; expect(labels).to.eql(expectedLabels); @@ -213,7 +213,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting square root scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '2,000', '4,000', '6,000', '8,000']; expect(labels).to.eql(expectedLabels); @@ -222,7 +222,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show ticks on selecting linear scale', async () => { await visEditor.selectYAxisScaleType(axisId, 'linear'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); log.debug(labels); const expectedLabels = ['0', '2,000', '4,000', '6,000', '8,000']; @@ -231,7 +231,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting linear scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '2,000', '4,000', '6,000', '8,000']; expect(labels).to.eql(expectedLabels); @@ -260,7 +260,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.clickBucket('X-axis'); log.debug('Aggregation = Date Histogram'); await visEditor.selectAggregation('Date Histogram'); - await visEditor.clickGo(true); + await visEditor.clickGo(); const title = await visChart.getYAxisTitle(xyChartSelector); expect(title).to.be('Serial Diff of Count'); }); @@ -268,7 +268,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should change y-axis label to custom', async () => { log.debug('set custom label of y-axis to "Custom"'); await visEditor.setCustomLabel('Custom', 1); - await visEditor.clickGo(true); + await visEditor.clickGo(); const title = await visChart.getYAxisTitle(xyChartSelector); expect(title).to.be('Custom'); }); @@ -283,7 +283,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should apply with selected bucket', async () => { log.debug('Metrics agg = Average Bucket'); await visEditor.selectAggregation('Average Bucket', 'metrics'); - await visEditor.clickGo(true); + await visEditor.clickGo(); const title = await visChart.getYAxisTitle(xyChartSelector); expect(title).to.be('Overall Average of Count'); }); @@ -291,7 +291,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should change sub metric custom label and calculate y-axis title', async () => { log.debug('set custom label of sub metric to "Cats"'); await visEditor.setCustomLabel('Cats', '1-metric'); - await visEditor.clickGo(true); + await visEditor.clickGo(); const title = await visChart.getYAxisTitle(xyChartSelector); expect(title).to.be('Overall Average of Cats'); }); @@ -299,7 +299,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should outer custom label', async () => { log.debug('set custom label to "Custom"'); await visEditor.setCustomLabel('Custom', 1); - await visEditor.clickGo(true); + await visEditor.clickGo(); const title = await visChart.getYAxisTitle(xyChartSelector); expect(title).to.be('Custom'); }); diff --git a/test/functional/apps/visualize/replaced_vislib_chart_types/_point_series_options.ts b/test/functional/apps/visualize/replaced_vislib_chart_types/_point_series_options.ts index 8f55f2f9285f..9e0aa41f71d8 100644 --- a/test/functional/apps/visualize/replaced_vislib_chart_types/_point_series_options.ts +++ b/test/functional/apps/visualize/replaced_vislib_chart_types/_point_series_options.ts @@ -58,7 +58,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { log.debug('Average memory value axis - ValueAxis-2'); await visEditor.setSeriesAxis(1, 'ValueAxis-2'); await visChart.waitForVisualizationRenderingStabilized(); - await visEditor.clickGo(true); + await visEditor.clickGo(); } describe('point series', function describeIndexTests() { @@ -121,7 +121,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('multiple chart types', function () { it('should change average series type to histogram', async function () { await visEditor.setSeriesType(1, 'histogram'); - await visEditor.clickGo(true); + await visEditor.clickGo(); const length = await visChart.getHistogramSeriesCount(xyChartSelector); expect(length).to.be(1); }); @@ -134,7 +134,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show category grid lines', async function () { await visEditor.toggleGridCategoryLines(); - await visEditor.clickGo(true); + await visEditor.clickGo(); const gridLines = await visChart.getGridLines(xyChartSelector); // FLAKY relaxing as depends on chart size/browser size and produce differences between local and CI // The objective here is to check whenever the grid lines are rendered, not the exact quantity @@ -147,7 +147,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show value axis grid lines', async function () { await visEditor.setGridValueAxis('ValueAxis-2'); await visEditor.toggleGridCategoryLines(); - await visEditor.clickGo(true); + await visEditor.clickGo(); const gridLines = await visChart.getGridLines(xyChartSelector); // FLAKY relaxing as depends on chart size/browser size and produce differences between local and CI // The objective here is to check whenever the grid lines are rendered, not the exact quantity @@ -169,21 +169,21 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectAggregation('Terms'); log.debug('Field = geo.src'); await visEditor.selectField('geo.src'); - await visEditor.clickGo(true); + await visEditor.clickGo(); log.debug('Open Options tab'); await visEditor.clickOptionsTab(); }); it('should show values on bar chart', async () => { await visEditor.toggleValuesOnChart(); - await visEditor.clickGo(true); + await visEditor.clickGo(); const values = await visChart.getChartValues(xyChartSelector); expect(values).to.eql(['2,592', '2,373', '1,194', '489', '415']); }); it('should hide values on bar chart', async () => { await visEditor.toggleValuesOnChart(); - await visEditor.clickGo(true); + await visEditor.clickGo(); const values = await visChart.getChartValues(xyChartSelector); expect(values.length).to.be(0); }); @@ -198,7 +198,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visualize.clickLineChart(); await visualize.clickNewSearch(); await visEditor.selectYAxisAggregation('Average', 'bytes', customLabel, 1); - await visEditor.clickGo(true); + await visEditor.clickGo(); await visEditor.clickMetricsAndAxes(); await visEditor.clickYAxisOptions('ValueAxis-1'); }); @@ -210,7 +210,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should render a custom axis title when one is set, overriding the custom label', async function () { await visEditor.setAxisTitle(axisTitle); - await visEditor.clickGo(true); + await visEditor.clickGo(); const title = await visChart.getYAxisTitle(xyChartSelector); expect(title).to.be(axisTitle); }); @@ -223,7 +223,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.clickDataTab(); await visEditor.toggleOpenEditor(1); await visEditor.setCustomLabel('test', 1); - await visEditor.clickGo(true); + await visEditor.clickGo(); await visEditor.clickMetricsAndAxes(); await visEditor.clickYAxisOptions('ValueAxis-1'); const title = await visChart.getYAxisTitle(xyChartSelector); @@ -331,7 +331,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.refresh(); // wait some time before trying to check for rendering count await header.awaitKibanaChrome(); - await visualize.clickRefresh(true); + await visualize.clickRefresh(); await visChart.waitForRenderingCount(); log.debug('getXAxisLabels'); diff --git a/test/functional/apps/visualize/replaced_vislib_chart_types/_timelion.ts b/test/functional/apps/visualize/replaced_vislib_chart_types/_timelion.ts index 6c96c9095f2f..9d9e437632b3 100644 --- a/test/functional/apps/visualize/replaced_vislib_chart_types/_timelion.ts +++ b/test/functional/apps/visualize/replaced_vislib_chart_types/_timelion.ts @@ -43,7 +43,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const initVisualization = async (expression: string, interval: string = '12h') => { await visEditor.setTimelionInterval(interval); await monacoEditor.setCodeEditorValue(expression); - await visEditor.clickGo(true); + await visEditor.clickGo(); }; it('should display correct data for specified index pattern and timefield', async () => { diff --git a/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart.ts b/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart.ts index 3d0f25b7870a..ef88a5f14cc2 100644 --- a/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart.ts +++ b/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart.ts @@ -52,7 +52,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { log.debug('Field = @timestamp'); await visEditor.selectField('@timestamp'); // leaving Interval set to Auto - await visEditor.clickGo(true); + await visEditor.clickGo(); }; describe('bar charts x axis tick labels', () => { @@ -63,7 +63,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.clickMetricsAndAxes(); await visEditor.selectXAxisPosition('left'); - await visEditor.clickGo(true); + await visEditor.clickGo(); // the getYAxisLabels helper always returns the labels on the left axis const leftLabels = await visChart.getYAxisLabels(xyChartSelector); @@ -79,13 +79,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectAggregation('Date Range'); await visEditor.selectField('@timestamp'); - await visEditor.clickGo(true); + await visEditor.clickGo(); const bottomLabels = await visChart.getXAxisLabels(xyChartSelector); expect(bottomLabels.length).to.be(1); await visEditor.clickMetricsAndAxes(); await visEditor.selectXAxisPosition('left'); - await visEditor.clickGo(true); + await visEditor.clickGo(); // the getYAxisLabels helper always returns the labels on the left axis const leftLabels = await visChart.getYAxisLabels(xyChartSelector); @@ -105,7 +105,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectField('@timestamp'); await visEditor.clickAddDateRange(); await visEditor.setDateRangeByIndex('1', 'now-2w/w', 'now-1w/w'); - await visEditor.clickGo(true); + await visEditor.clickGo(); const bottomLabels = await visChart.getXAxisLabels(xyChartSelector); expect(bottomLabels.length).to.be(2); }); @@ -194,7 +194,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.toggleOpenEditor(2); await visEditor.clickDropPartialBuckets(); - await visEditor.clickGo(true); + await visEditor.clickGo(); expectedChartValues = [ 218, 341, 440, 480, 517, 522, 446, 403, 321, 258, 172, 95, 55, 38, 24, 3, 4, 11, 14, 17, 38, @@ -222,7 +222,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.clickYAxisOptions(axisId); await visEditor.selectYAxisScaleType(axisId, 'log'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabelsAsNumbers(xyChartSelector); const minLabel = 1; @@ -235,7 +235,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting log scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabelsAsNumbers(xyChartSelector); const minLabel = 1; @@ -249,7 +249,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show ticks on selecting square root scale', async () => { await visEditor.selectYAxisScaleType(axisId, 'square root'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '200', '400', '600', '800', '1,000', '1,200', '1,400']; expect(labels).to.eql(expectedLabels); @@ -257,7 +257,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting square root scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '200', '400', '600', '800', '1,000', '1,200', '1,400']; expect(labels).to.eql(expectedLabels); @@ -266,7 +266,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show ticks on selecting linear scale', async () => { await visEditor.selectYAxisScaleType(axisId, 'linear'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); log.debug(labels); const expectedLabels = ['0', '200', '400', '600', '800', '1,000', '1,200', '1,400']; @@ -275,7 +275,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting linear scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '200', '400', '600', '800', '1,000', '1,200', '1,400']; expect(labels).to.eql(expectedLabels); @@ -290,7 +290,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectYAxisMode('percentage'); await visEditor.changeYAxisShowCheckbox(axisId, true); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); expect(labels[0]).to.eql('0%'); expect(labels[labels.length - 1]).to.eql('100%'); @@ -306,7 +306,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectAggregation('Terms'); await visEditor.selectField('response.raw'); await visChart.waitForVisualizationRenderingStabilized(); - await visEditor.clickGo(true); + await visEditor.clickGo(); const expectedEntries = ['200', '404', '503']; // sorting order aligned with the reading direction const legendEntries = await visChart.getLegendEntriesXYCharts(xyChartSelector); @@ -316,7 +316,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should allow custom sorting of series', async () => { await visEditor.toggleOpenEditor(1, 'false'); await visEditor.selectCustomSortMetric(3, 'Min', 'bytes'); - await visEditor.clickGo(true); + await visEditor.clickGo(); const expectedEntries = ['404', '200', '503']; const legendEntries = await visChart.getLegendEntriesXYCharts(xyChartSelector); @@ -324,7 +324,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should correctly filter by legend', async () => { - await visChart.filterLegend('200', true); + await visChart.filterLegend('200'); await visChart.waitForVisualization(); const legendEntries = await visChart.getLegendEntriesXYCharts(xyChartSelector); const expectedEntries = ['200']; @@ -349,7 +349,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectAggregation('Terms'); await visEditor.selectField('machine.os'); await visChart.waitForVisualizationRenderingStabilized(); - await visEditor.clickGo(true); + await visEditor.clickGo(); const expectedEntries = [ '200 - win 8', @@ -376,7 +376,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // this will avoid issues with the play tooltip covering the disable agg button await testSubjects.scrollIntoView('metricsAggGroup'); await visEditor.toggleDisabledAgg(3); - await visEditor.clickGo(true); + await visEditor.clickGo(); const expectedEntries = ['win 8', 'win xp', 'ios', 'osx', 'win 7']; const legendEntries = await visChart.getLegendEntriesXYCharts(xyChartSelector); @@ -392,7 +392,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.toggleOpenEditor(1); await visEditor.selectAggregation('Derivative', 'metrics'); await visChart.waitForVisualizationRenderingStabilized(); - await visEditor.clickGo(true); + await visEditor.clickGo(); const expectedEntries = ['Derivative of Count']; const legendEntries = await visChart.getLegendEntriesXYCharts(xyChartSelector); diff --git a/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart_nontimeindex.ts b/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart_nontimeindex.ts index 15ff0fc18d8e..f5cff915168f 100644 --- a/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart_nontimeindex.ts +++ b/test/functional/apps/visualize/replaced_vislib_chart_types/_vertical_bar_chart_nontimeindex.ts @@ -43,7 +43,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.selectField('@timestamp'); await visEditor.setInterval('3h', { type: 'custom' }); await visChart.waitForVisualizationRenderingStabilized(); - await visEditor.clickGo(true); + await visEditor.clickGo(); }; before(async () => { @@ -117,7 +117,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await visEditor.clickYAxisOptions(axisId); await visEditor.selectYAxisScaleType(axisId, 'log'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabelsAsNumbers(xyChartSelector); const minLabel = 1; const maxLabel = 900; @@ -129,7 +129,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting log scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabelsAsNumbers(xyChartSelector); const minLabel = 1; const maxLabel = 900; @@ -142,7 +142,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show ticks on selecting square root scale', async () => { await visEditor.selectYAxisScaleType(axisId, 'square root'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '200', '400', '600', '800', '1,000', '1,200', '1,400']; expect(labels).to.eql(expectedLabels); @@ -150,7 +150,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting square root scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '200', '400', '600', '800', '1,000', '1,200', '1,400']; expect(labels).to.eql(expectedLabels); @@ -159,7 +159,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show ticks on selecting linear scale', async () => { await visEditor.selectYAxisScaleType(axisId, 'linear'); await visEditor.changeYAxisFilterLabelsCheckbox(axisId, false); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); log.debug(labels); const expectedLabels = ['0', '200', '400', '600', '800', '1,000', '1,200', '1,400']; @@ -168,7 +168,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show filtered ticks on selecting linear scale', async () => { await visEditor.changeYAxisFilterLabelsCheckbox(axisId, true); - await visEditor.clickGo(true); + await visEditor.clickGo(); const labels = await visChart.getYAxisLabels(xyChartSelector); const expectedLabels = ['0', '200', '400', '600', '800', '1,000', '1,200', '1,400']; expect(labels).to.eql(expectedLabels); @@ -186,7 +186,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await header.waitUntilLoadingHasFinished(); await common.sleep(1003); - await visEditor.clickGo(true); + await visEditor.clickGo(); await header.waitUntilLoadingHasFinished(); const expectedEntries = ['200', '404', '503']; // sorting order aligned with reading direction top-bottom @@ -213,7 +213,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await header.waitUntilLoadingHasFinished(); await common.sleep(1003); - await visEditor.clickGo(true); + await visEditor.clickGo(); await header.waitUntilLoadingHasFinished(); const expectedEntries = [ @@ -239,7 +239,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show correct series when disabling first agg', async function () { await visEditor.toggleDisabledAgg(3); - await visEditor.clickGo(true); + await visEditor.clickGo(); await header.waitUntilLoadingHasFinished(); const expectedEntries = ['win 8', 'win xp', 'ios', 'osx', 'win 7']; @@ -258,7 +258,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await header.waitUntilLoadingHasFinished(); await common.sleep(1003); - await visEditor.clickGo(true); + await visEditor.clickGo(); await header.waitUntilLoadingHasFinished(); const expectedEntries = ['Derivative of Count']; diff --git a/test/functional/page_objects/unified_field_list.ts b/test/functional/page_objects/unified_field_list.ts index 14006c8c5d62..4751769f717b 100644 --- a/test/functional/page_objects/unified_field_list.ts +++ b/test/functional/page_objects/unified_field_list.ts @@ -226,6 +226,16 @@ export class UnifiedFieldListPageObject extends FtrService { await this.testSubjects.missingOrFail(`fieldVisualize-${field}`); } + public async clickFieldListAddBreakdownField(field: string) { + const addBreakdownFieldTestSubj = `fieldPopoverHeader_addBreakdownField-${field}`; + if (!(await this.testSubjects.exists(addBreakdownFieldTestSubj))) { + // field has to be open + await this.clickFieldListItem(field); + } + await this.testSubjects.click(addBreakdownFieldTestSubj); + await this.header.waitUntilLoadingHasFinished(); + } + public async clickFieldListPlusFilter(field: string, value: string) { const plusFilterTestSubj = `plus-${field}-${value}`; if (!(await this.testSubjects.exists(plusFilterTestSubj))) { diff --git a/test/functional/page_objects/visualize_chart_page.ts b/test/functional/page_objects/visualize_chart_page.ts index 9fe9afb32d86..31d33eca7da3 100644 --- a/test/functional/page_objects/visualize_chart_page.ts +++ b/test/functional/page_objects/visualize_chart_page.ts @@ -153,20 +153,17 @@ export class VisualizeChartPageObject extends FtrService { return values.sort((a, b) => a.x - b.x).map(({ y }) => y); } - private async toggleLegend(force = false) { - const isVisTypePieChart = await this.isNewLibraryChart(partitionVisChartSelector); - const legendSelector = force || isVisTypePieChart ? '.echLegend' : '.visLegend'; - + private async toggleLegend() { await this.retry.try(async () => { - const isVisible = await this.find.existsByCssSelector(legendSelector); + const isVisible = await this.find.existsByCssSelector('.echLegend'); if (!isVisible) { await this.testSubjects.click('vislibToggleLegend'); } }); } - public async filterLegend(name: string, force = false) { - await this.toggleLegend(force); + public async filterLegend(name: string) { + await this.toggleLegend(); await this.testSubjects.click(`legend-${name}`); // wait for a short amount of time for popover to stabilize as there is no good way to check for that await this.common.sleep(250); @@ -189,23 +186,13 @@ export class VisualizeChartPageObject extends FtrService { } public async doesSelectedLegendColorExistForPie(matchingColor: string) { - if (await this.isNewLibraryChart(partitionVisChartSelector)) { - const hexMatchingColor = chroma(matchingColor).hex().toUpperCase(); - const slices = - (await this.getEsChartDebugState(partitionVisChartSelector))?.partition?.[0]?.partitions ?? - []; - return slices.some(({ color }) => { - return hexMatchingColor === chroma(color).hex().toUpperCase(); - }); - } - - return await this.testSubjects.exists(`legendSelectedColor-${matchingColor}`); - } - - public async expectError() { - if (!this.isNewLibraryChart(partitionVisChartSelector)) { - await this.testSubjects.existOrFail('vislibVisualizeError'); - } + const hexMatchingColor = chroma(matchingColor).hex().toUpperCase(); + const slices = + (await this.getEsChartDebugState(partitionVisChartSelector))?.partition?.[0]?.partitions ?? + []; + return slices.some(({ color }) => { + return hexMatchingColor === chroma(color).hex().toUpperCase(); + }); } public async getVisualizationRenderingCount() { @@ -305,17 +292,11 @@ export class VisualizeChartPageObject extends FtrService { public async openLegendOptionColorsForPie(name: string, chartSelector: string) { await this.waitForVisualizationRenderingStabilized(); await this.retry.try(async () => { - if (await this.isNewLibraryChart(partitionVisChartSelector)) { - const chart = await this.find.byCssSelector(chartSelector); - const legendItemColor = await chart.findByCssSelector( - `[data-ech-series-name="${name}"] .echLegendItem__color` - ); - await legendItemColor.click(); - } else { - // This click has been flaky in opening the legend, hence the this.retry. See - // https://github.com/elastic/kibana/issues/17468 - await this.testSubjects.click(`legend-${name}`); - } + const chart = await this.find.byCssSelector(chartSelector); + const legendItemColor = await chart.findByCssSelector( + `[data-ech-series-name="${name}"] .echLegendItem__color` + ); + await legendItemColor.click(); await this.waitForVisualizationRenderingStabilized(); // arbitrary color chosen, any available would do diff --git a/test/functional/page_objects/visualize_editor_page.ts b/test/functional/page_objects/visualize_editor_page.ts index 9f9b5cf74be9..95ee763b7de1 100644 --- a/test/functional/page_objects/visualize_editor_page.ts +++ b/test/functional/page_objects/visualize_editor_page.ts @@ -64,8 +64,8 @@ export class VisualizeEditorPageObject extends FtrService { await this.visChart.waitForVisualizationRenderingStabilized(); } - public async clickGo(isNewChartLibrary = false) { - if ((await this.visChart.isNewChartsLibraryEnabled()) || isNewChartLibrary) { + public async clickGo(isLegacyChartLib = false) { + if ((await this.visChart.isNewChartsLibraryEnabled()) || !isLegacyChartLib) { await this.elasticChart.setNewChartUiDebugFlag(); } diff --git a/test/functional/page_objects/visualize_page.ts b/test/functional/page_objects/visualize_page.ts index 1f6c9cc11c47..d565c5168641 100644 --- a/test/functional/page_objects/visualize_page.ts +++ b/test/functional/page_objects/visualize_page.ts @@ -52,7 +52,7 @@ export class VisualizePageObject extends FtrService { remoteEsPrefix = 'ftr-remote:'; defaultIndexString = 'logstash-*'; - public async initTests(isNewLibrary = false) { + public async initTests(isLegacyChart = false) { await this.kibanaServer.savedObjects.clean({ types: ['visualization'] }); await this.kibanaServer.importExport.load( 'test/functional/fixtures/kbn_archiver/visualize.json' @@ -61,7 +61,7 @@ export class VisualizePageObject extends FtrService { await this.kibanaServer.uiSettings.replace({ defaultIndex: this.defaultIndexString, [FORMATS_UI_SETTINGS.FORMAT_BYTES_DEFAULT_PATTERN]: '0,0.[000]b', - 'visualization:visualize:legacyHeatmapChartsLibrary': !isNewLibrary, + 'visualization:visualize:legacyHeatmapChartsLibrary': isLegacyChart, 'histogram:maxBars': 100, }); } @@ -149,8 +149,8 @@ export class VisualizePageObject extends FtrService { }); } - public async clickRefresh(isNewChartLibrary = false) { - if ((await this.visChart.isNewChartsLibraryEnabled()) || isNewChartLibrary) { + public async clickRefresh(isLegacyChart = false) { + if ((await this.visChart.isNewChartsLibraryEnabled()) || !isLegacyChart) { await this.elasticChart.setNewChartUiDebugFlag(); } await this.queryBar.clickQuerySubmitButton(); @@ -517,14 +517,6 @@ export class VisualizePageObject extends FtrService { await this.testSubjects.click('visualizesaveAndReturnButton'); } - public async getDeprecationWarningStatus() { - if (await this.visChart.isNewChartsLibraryEnabled()) { - await this.testSubjects.missingOrFail('vizDeprecationWarning'); - } else { - await this.testSubjects.existOrFail('vizDeprecationWarning'); - } - } - public async linkedToOriginatingApp() { await this.header.waitUntilLoadingHasFinished(); await this.testSubjects.existOrFail('visualizesaveAndReturnButton'); diff --git a/test/functional/services/visualizations/pie_chart.ts b/test/functional/services/visualizations/pie_chart.ts index d5b1a636d2b2..f58970b9218f 100644 --- a/test/functional/services/visualizations/pie_chart.ts +++ b/test/functional/services/visualizations/pie_chart.ts @@ -8,7 +8,6 @@ */ import expect from '@kbn/expect'; -import { isNil } from 'lodash'; import { DebugState } from '@elastic/charts'; import { FtrService } from '../../ftr_provider_context'; @@ -30,36 +29,24 @@ export class PieChartService extends FtrService { async clickOnPieSlice(name?: string) { this.log.debug(`PieChart.clickOnPieSlice(${name})`); - if (await this.visChart.isNewLibraryChart(partitionVisChartSelector)) { - const slices = this.getSlices( - await this.visChart.getEsChartDebugState(partitionVisChartSelector) - ); - let sliceLabel = name || slices[0].name; - if (name === 'Other') { - sliceLabel = '__other__'; - } - const pieSlice = slices.find((slice) => String(slice.name) === sliceLabel); - const pie = await this.testSubjects.find(partitionVisChartSelector); - if (pieSlice) { - const pieSize = await pie.getSize(); - const pieHeight = pieSize.height; - const pieWidth = pieSize.width; - await pie.clickMouseButton({ - xOffset: pieSlice.coords[0] - Math.floor(pieWidth / 2), - yOffset: pieSlice.coords[1] - Math.floor(pieHeight / 2), - }); - } - } else { - if (name) { - await this.testSubjects.click(`pieSlice-${name.split(' ').join('-')}`); - } else { - // If no pie slice has been provided, find the first one available. - await this.retry.try(async () => { - const slices = await this.find.allByCssSelector('svg > g > g.arcs > path.slice'); - this.log.debug('Slices found:' + slices.length); - return slices[0].click(); - }); - } + + const slices = this.getSlices( + await this.visChart.getEsChartDebugState(partitionVisChartSelector) + ); + let sliceLabel = name || slices[0].name; + if (name === 'Other') { + sliceLabel = '__other__'; + } + const pieSlice = slices.find((slice) => String(slice.name) === sliceLabel); + const pie = await this.testSubjects.find(partitionVisChartSelector); + if (pieSlice) { + const pieSize = await pie.getSize(); + const pieHeight = pieSize.height; + const pieWidth = pieSize.width; + await pie.clickMouseButton({ + xOffset: pieSlice.coords[0] - Math.floor(pieWidth / 2), + yOffset: pieSlice.coords[1] - Math.floor(pieHeight / 2), + }); } } @@ -100,12 +87,8 @@ export class PieChartService extends FtrService { async getPieSliceStyle(name: string) { this.log.debug(`VisualizePage.getPieSliceStyle(${name})`); - if (await this.visChart.isNewLibraryChart(partitionVisChartSelector)) { - const selectedSlice = await this.getSelectedSlice(name); - return selectedSlice[0]?.color; - } - const pieSlice = await this.getPieSlice(name); - return await pieSlice.getAttribute('style'); + const selectedSlice = await this.getSelectedSlice(name); + return selectedSlice[0]?.color; } async getAllPieSlicesColors() { @@ -121,27 +104,8 @@ export class PieChartService extends FtrService { async getAllPieSliceColor(name: string) { this.log.debug(`VisualizePage.getAllPieSliceColor(${name})`); - if (await this.visChart.isNewLibraryChart(partitionVisChartSelector)) { - const selectedSlice = await this.getSelectedSlice(name); - return selectedSlice.map((slice) => slice.color); - } - const pieSlices = await this.getAllPieSlices(name); - const slicesStyles = await Promise.all( - pieSlices.map(async (pieSlice) => (await pieSlice.getAttribute('style')) ?? '') - ); - return slicesStyles - .map( - (styles) => - styles.split(';').reduce>((styleAsObj, style) => { - const stylePair = style.split(':'); - if (stylePair.length !== 2) { - return styleAsObj; - } - styleAsObj[stylePair[0].trim()] = stylePair[1].trim(); - return styleAsObj; - }, {}).fill // in vislib the color is available on the `fill` style prop - ) - .filter((d) => !isNil(d)); + const selectedSlice = await this.getSelectedSlice(name); + return selectedSlice.map((slice) => slice.color); } async getPieChartData() { @@ -155,57 +119,41 @@ export class PieChartService extends FtrService { await this.inspector.expectTableData(expectedTableData); } - async getPieChartLabels(isNewLibrary: boolean = true) { - if (isNewLibrary) { - const slices = this.getSlices( - await this.visChart.getEsChartDebugState(partitionVisChartSelector) - ); - return slices.map((slice) => { - if (slice.name === '__missing__') { - return 'Missing'; - } else if (slice.name === '__other__') { - return 'Other'; - } else if (typeof slice.name === 'number') { - // debugState of escharts returns the numbers without comma - const val = slice.name as number; - return val.toString().replace(/\B(? await chart.getAttribute('data-label')) + async getPieChartLabels() { + const slices = this.getSlices( + await this.visChart.getEsChartDebugState(partitionVisChartSelector) ); + return slices.map((slice) => { + if (slice.name === '__missing__') { + return 'Missing'; + } else if (slice.name === '__other__') { + return 'Other'; + } else if (typeof slice.name === 'number') { + // debugState of escharts returns the numbers without comma + const val = slice.name as number; + return val.toString().replace(/\B(? { - return slice.value; - }); - } - const chartTypes = await this.find.allByCssSelector('path.slice', this.defaultFindTimeout * 2); - return await Promise.all( - chartTypes.map(async (chart) => await chart.getAttribute('data-value')) + const slices = this.getSlices( + await this.visChart.getEsChartDebugState(partitionVisChartSelector) ); + return slices.map((slice) => { + return slice.value; + }); } - async getPieSliceCount(isNewLibrary: boolean = true) { + async getPieSliceCount() { this.log.debug('PieChart.getPieSliceCount'); - if (isNewLibrary) { - const slices = this.getSlices( - await this.visChart.getEsChartDebugState(partitionVisChartSelector) - ); - return slices?.length; - } - const slices = await this.find.allByCssSelector('svg > g > g.arcs > path.slice'); - return slices.length; + const slices = this.getSlices( + await this.visChart.getEsChartDebugState(partitionVisChartSelector) + ); + return slices?.length; } async getSliceCountForAllPies() { @@ -234,10 +182,10 @@ export class PieChartService extends FtrService { expect(slices.length).to.be(expectedCount); } - async expectPieSliceCount(expectedCount: number, isNewLibrary: boolean = true) { + async expectPieSliceCount(expectedCount: number) { this.log.debug(`PieChart.expectPieSliceCount(${expectedCount})`); await this.retry.try(async () => { - const slicesCount = await this.getPieSliceCount(isNewLibrary); + const slicesCount = await this.getPieSliceCount(); expect(slicesCount).to.be(expectedCount); }); } @@ -254,10 +202,10 @@ export class PieChartService extends FtrService { expect(noResult).to.be(true); } - async expectPieChartLabels(expectedLabels: string[], isNewLibrary: boolean = true) { + async expectPieChartLabels(expectedLabels: string[]) { this.log.debug(`PieChart.expectPieChartLabels(${expectedLabels.join(',')})`); await this.retry.try(async () => { - const pieData = await this.getPieChartLabels(isNewLibrary); + const pieData = await this.getPieChartLabels(); expect(pieData.sort()).to.eql(expectedLabels); }); } diff --git a/tsconfig.base.json b/tsconfig.base.json index 7b1bc834fcc2..68faf44ed74d 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1034,6 +1034,8 @@ "@kbn/import-locator/*": ["packages/kbn-import-locator/*"], "@kbn/import-resolver": ["packages/kbn-import-resolver"], "@kbn/import-resolver/*": ["packages/kbn-import-resolver/*"], + "@kbn/index-lifecycle-management-common-shared": ["x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared"], + "@kbn/index-lifecycle-management-common-shared/*": ["x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/*"], "@kbn/index-lifecycle-management-plugin": ["x-pack/plugins/index_lifecycle_management"], "@kbn/index-lifecycle-management-plugin/*": ["x-pack/plugins/index_lifecycle_management/*"], "@kbn/index-management-plugin": ["x-pack/plugins/index_management"], diff --git a/x-pack/packages/ai-infra/product-doc-artifact-builder/src/tasks/install_elser.ts b/x-pack/packages/ai-infra/product-doc-artifact-builder/src/tasks/install_elser.ts index 037a9e809d1e..09dc85b81619 100644 --- a/x-pack/packages/ai-infra/product-doc-artifact-builder/src/tasks/install_elser.ts +++ b/x-pack/packages/ai-infra/product-doc-artifact-builder/src/tasks/install_elser.ts @@ -60,7 +60,6 @@ const waitUntilDeployed = async ({ model_id: modelId, }); const deploymentStats = statsRes.trained_model_stats[0]?.deployment_stats; - // @ts-expect-error deploymentStats.nodes not defined as array even if it is. if (!deploymentStats || deploymentStats.nodes.length === 0) { await sleep(delay); continue; diff --git a/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/README.md b/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/README.md new file mode 100644 index 000000000000..66d1ff7e3c8f --- /dev/null +++ b/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/README.md @@ -0,0 +1,3 @@ +# @kbn/index-lifecycle-management-common-shared + +Contains types and functions used and exported by the index lifecycle management plugin. Primarily used to address dependency issues. diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/index.ts b/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/index.ts similarity index 58% rename from x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/index.ts rename to x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/index.ts index 96503dcac381..044ab18aa34d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/index.ts +++ b/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/index.ts @@ -5,7 +5,5 @@ * 2.0. */ -import type { SortColumnTimeline } from '../../../../../../common/types/timeline'; - -/** Specifies which column the timeline is sorted on */ -export type Sort = SortColumnTimeline; +export const ILM_LOCATOR_ID = 'ILM_LOCATOR_ID'; +export * from './src/policies'; diff --git a/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/kibana.jsonc b/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/kibana.jsonc new file mode 100644 index 000000000000..dfaef1d0dfb9 --- /dev/null +++ b/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/index-lifecycle-management-common-shared", + "owner": "@elastic/kibana-management" +} diff --git a/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/package.json b/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/package.json new file mode 100644 index 000000000000..9c3e7c99dd7d --- /dev/null +++ b/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/index-lifecycle-management-common-shared", + "private": true, + "version": "1.0.0", + "license": "Elastic License 2.0" +} diff --git a/x-pack/plugins/index_lifecycle_management/common/types/policies.ts b/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts similarity index 100% rename from x-pack/plugins/index_lifecycle_management/common/types/policies.ts rename to x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/src/policies.ts diff --git a/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/tsconfig.json b/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/tsconfig.json new file mode 100644 index 000000000000..12a691a15cc4 --- /dev/null +++ b/x-pack/packages/index-lifecycle-management/index_lifecycle_management_common_shared/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + ] +} diff --git a/x-pack/packages/kbn-ai-assistant/src/buttons/new_chat_button.tsx b/x-pack/packages/kbn-ai-assistant/src/buttons/new_chat_button.tsx index 3e515e87c219..60e37d85b92d 100644 --- a/x-pack/packages/kbn-ai-assistant/src/buttons/new_chat_button.tsx +++ b/x-pack/packages/kbn-ai-assistant/src/buttons/new_chat_button.tsx @@ -19,7 +19,7 @@ export function NewChatButton( {...nextProps} > {i18n.translate('xpack.aiAssistant.newChatButton', { - defaultMessage: 'New chat', + defaultMessage: 'New conversation', })} ) : ( diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.tsx index 320beb1ca6b0..f7d8b3b20c43 100644 --- a/x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.tsx +++ b/x-pack/packages/kbn-ai-assistant/src/chat/chat_flyout.tsx @@ -234,14 +234,14 @@ export function ChatFlyout({ {i18n.translate('xpack.aiAssistant.disclaimer.disclaimerLabel', { defaultMessage: - "This chat is powered by an integration with your LLM provider. LLMs are known to sometimes present incorrect information as if it's correct. Elastic supports configuration and connection to the LLM provider and your knowledge base, but is not responsible for the LLM's responses.", + "This conversation is powered by an integration with your LLM provider. LLMs are known to sometimes present incorrect information as if it's correct. Elastic supports configuration and connection to the LLM provider and your knowledge base, but is not responsible for the LLM's responses.", })} ); diff --git a/x-pack/packages/kbn-ai-assistant/src/utils/get_timeline_items_from_conversation.test.tsx b/x-pack/packages/kbn-ai-assistant/src/utils/get_timeline_items_from_conversation.test.tsx index 337c11419209..6a304430103a 100644 --- a/x-pack/packages/kbn-ai-assistant/src/utils/get_timeline_items_from_conversation.test.tsx +++ b/x-pack/packages/kbn-ai-assistant/src/utils/get_timeline_items_from_conversation.test.tsx @@ -18,7 +18,7 @@ const mockChatService = createMockChatService(); let items: ReturnType; -function Providers({ children }: { children: React.ReactElement }) { +function Providers({ children }: { children: React.ReactNode }) { return ( schema.oneOf([entityNodeDataSchema, groupNodeDataSchema, labelNodeDataSchema]) ), edges: schema.arrayOf(edgeDataSchema), + messages: schema.maybe( + schema.arrayOf(schema.oneOf([schema.literal(ApiMessageCode.ReachedNodesLimit)])) + ), }); export const colorSchema = schema.oneOf([ diff --git a/x-pack/packages/kbn-cloud-security-posture/common/tsconfig.json b/x-pack/packages/kbn-cloud-security-posture/common/tsconfig.json index c7cf1e9208bf..ebec9929559f 100644 --- a/x-pack/packages/kbn-cloud-security-posture/common/tsconfig.json +++ b/x-pack/packages/kbn-cloud-security-posture/common/tsconfig.json @@ -20,5 +20,6 @@ "@kbn/i18n", "@kbn/analytics", "@kbn/usage-collection-plugin", + "@kbn/es-query", ] } diff --git a/x-pack/packages/kbn-cloud-security-posture/common/types/graph/v1.ts b/x-pack/packages/kbn-cloud-security-posture/common/types/graph/v1.ts index 48d1d1c49fd0..f97d11b34732 100644 --- a/x-pack/packages/kbn-cloud-security-posture/common/types/graph/v1.ts +++ b/x-pack/packages/kbn-cloud-security-posture/common/types/graph/v1.ts @@ -6,6 +6,7 @@ */ import type { TypeOf } from '@kbn/config-schema'; +import type { BoolQuery } from '@kbn/es-query'; import { colorSchema, edgeDataSchema, @@ -17,13 +18,21 @@ import { nodeShapeSchema, } from '../../schema/graph/v1'; -export type GraphRequest = TypeOf; -export type GraphResponse = TypeOf; +export type GraphRequest = Omit, 'query.esQuery'> & { + query: { esQuery?: { bool: Partial } }; +}; +export type GraphResponse = Omit, 'messages'> & { + messages?: ApiMessageCode[]; +}; export type Color = typeof colorSchema.type; export type NodeShape = TypeOf; +export enum ApiMessageCode { + ReachedNodesLimit = 'REACHED_NODES_LIMIT', +} + export type EntityNodeDataModel = TypeOf; export type GroupNodeDataModel = TypeOf; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/range_picker/ranges.ts b/x-pack/packages/kbn-langchain/server/tracers/telemetry/index.ts similarity index 57% rename from x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/range_picker/ranges.ts rename to x-pack/packages/kbn-langchain/server/tracers/telemetry/index.ts index a174207b2b05..079c0e9a3308 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/range_picker/ranges.ts +++ b/x-pack/packages/kbn-langchain/server/tracers/telemetry/index.ts @@ -5,7 +5,4 @@ * 2.0. */ -import * as i18n from './translations'; - -/** Enables runtime enumeration of valid `Range`s */ -export const Ranges: string[] = [i18n.ONE_DAY, i18n.ONE_WEEK, i18n.ONE_MONTH, i18n.ONE_YEAR]; +export { TelemetryTracer } from './telemetry_tracer'; diff --git a/x-pack/packages/kbn-langchain/server/tracers/telemetry/telemetry_tracer.test.ts b/x-pack/packages/kbn-langchain/server/tracers/telemetry/telemetry_tracer.test.ts new file mode 100644 index 000000000000..bca293ba9957 --- /dev/null +++ b/x-pack/packages/kbn-langchain/server/tracers/telemetry/telemetry_tracer.test.ts @@ -0,0 +1,204 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AnalyticsServiceSetup, Logger } from '@kbn/core/server'; +import { TelemetryTracer, TelemetryParams } from './telemetry_tracer'; +import { Run } from 'langsmith/schemas'; +import { loggerMock } from '@kbn/logging-mocks'; + +const mockRun = { + inputs: { + responseLanguage: 'English', + conversationId: 'db8f74c5-7dca-43a3-b592-d56f219dffab', + llmType: 'openai', + isStream: false, + isOssModel: false, + }, + outputs: { + input: + 'Generate an ESQL query to find documents with `host.name` that contains my favorite color', + lastNode: 'agent', + steps: [ + { + action: { + tool: 'KnowledgeBaseRetrievalTool', + toolInput: { + query: "user's favorite color", + }, + }, + observation: + '"[{\\"pageContent\\":\\"favorite color is blue\\",\\"metadata\\":{\\"source\\":\\"conversation\\",\\"required\\":false,\\"kbResource\\":\\"user\\"}},{\\"pageContent\\":\\"favorite food is pizza\\",\\"metadata\\":{\\"source\\":\\"conversation\\",\\"required\\":false,\\"kbResource\\":\\"user\\"}}]"', + }, + { + action: { + tool: 'NaturalLanguageESQLTool', + toolInput: { + question: 'Generate an ESQL query to find documents with host.name that contains blue', + }, + }, + observation: + '"To find documents with `host.name` that contains \\"blue\\", you can use the `LIKE` operator with wildcards. Here is the ES|QL query:\\n\\n```esql\\nFROM your_index\\n| WHERE host.name LIKE \\"*blue*\\"\\n```\\n\\nReplace `your_index` with the actual name of your index. This query will filter documents where the `host.name` field contains the substring \\"blue\\"."', + }, + { + action: { + tool: 'KnowledgeBaseRetrievalTool', + toolInput: { + query: "user's favorite food", + }, + }, + observation: + '"[{\\"pageContent\\":\\"favorite color is blue\\",\\"metadata\\":{\\"source\\":\\"conversation\\",\\"required\\":false,\\"kbResource\\":\\"user\\"}},{\\"pageContent\\":\\"favorite food is pizza\\",\\"metadata\\":{\\"source\\":\\"conversation\\",\\"required\\":false,\\"kbResource\\":\\"user\\"}}]"', + }, + { + action: { + tool: 'CustomIndexTool', + toolInput: { + query: 'query about index', + }, + }, + observation: '"Wow this is totally cool."', + }, + { + action: { + tool: 'CustomIndexTool', + toolInput: { + query: 'query about index', + }, + }, + observation: '"Wow this is totally cool."', + }, + { + action: { + tool: 'CustomIndexTool', + toolInput: { + query: 'query about index', + }, + }, + observation: '"Wow this is totally cool."', + }, + ], + hasRespondStep: false, + agentOutcome: { + returnValues: { + output: + 'To find documents with `host.name` that contains your favorite color "blue", you can use the `LIKE` operator with wildcards. Here is the ES|QL query:\n\n```esql\nFROM your_index\n| WHERE host.name LIKE "*blue*"\n```\n\nReplace `your_index` with the actual name of your index. This query will filter documents where the `host.name` field contains the substring "blue".', + }, + log: 'To find documents with `host.name` that contains your favorite color "blue", you can use the `LIKE` operator with wildcards. Here is the ES|QL query:\n\n```esql\nFROM your_index\n| WHERE host.name LIKE "*blue*"\n```\n\nReplace `your_index` with the actual name of your index. This query will filter documents where the `host.name` field contains the substring "blue".', + }, + messages: [], + chatTitle: 'Welcome', + llmType: 'openai', + isStream: false, + isOssModel: false, + conversation: { + timestamp: '2024-11-07T17:37:07.400Z', + createdAt: '2024-11-07T17:37:07.400Z', + users: [ + { + id: 'u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0', + name: 'elastic', + }, + ], + title: 'Welcome', + category: 'assistant', + apiConfig: { + connectorId: 'my-gpt4o-ai', + actionTypeId: '.gen-ai', + }, + isDefault: true, + messages: [ + { + timestamp: '2024-11-07T22:47:45.994Z', + content: + 'Generate an ESQL query to find documents with `host.name` that contains my favorite color', + role: 'user', + }, + ], + updatedAt: '2024-11-08T17:01:21.958Z', + replacements: {}, + namespace: 'default', + id: 'db8f74c5-7dca-43a3-b592-d56f219dffab', + }, + conversationId: 'db8f74c5-7dca-43a3-b592-d56f219dffab', + responseLanguage: 'English', + }, + end_time: 1731085297190, + start_time: 1731085289113, +} as unknown as Run; +const elasticTools = [ + 'AlertCountsTool', + 'NaturalLanguageESQLTool', + 'KnowledgeBaseRetrievalTool', + 'KnowledgeBaseWriteTool', + 'OpenAndAcknowledgedAlertsTool', + 'SecurityLabsKnowledgeBaseTool', +]; +const mockLogger = loggerMock.create(); + +describe('TelemetryTracer', () => { + let telemetry: AnalyticsServiceSetup; + let logger: Logger; + let telemetryParams: TelemetryParams; + let telemetryTracer: TelemetryTracer; + const reportEvent = jest.fn(); + beforeEach(() => { + telemetry = { + reportEvent, + } as unknown as AnalyticsServiceSetup; + logger = mockLogger; + telemetryParams = { + eventType: 'INVOKE_AI_SUCCESS', + assistantStreamingEnabled: true, + actionTypeId: '.gen-ai', + isEnabledKnowledgeBase: true, + model: 'test_model', + }; + telemetryTracer = new TelemetryTracer( + { + elasticTools, + telemetry, + telemetryParams, + totalTools: 9, + }, + logger + ); + }); + + it('should initialize correctly', () => { + expect(telemetryTracer.name).toBe('telemetry_tracer'); + expect(telemetryTracer.elasticTools).toEqual(elasticTools); + expect(telemetryTracer.telemetry).toBe(telemetry); + expect(telemetryTracer.telemetryParams).toBe(telemetryParams); + expect(telemetryTracer.totalTools).toBe(9); + }); + + it('should not log and report event on chain end if parent_run_id exists', async () => { + await telemetryTracer.onChainEnd({ ...mockRun, parent_run_id: '123' }); + + expect(logger.get().debug).not.toHaveBeenCalled(); + expect(telemetry.reportEvent).not.toHaveBeenCalled(); + }); + + it('should log and report event on chain end', async () => { + await telemetryTracer.onChainEnd(mockRun); + + expect(logger.get().debug).toHaveBeenCalledWith(expect.any(Function)); + expect(telemetry.reportEvent).toHaveBeenCalledWith('INVOKE_AI_SUCCESS', { + assistantStreamingEnabled: true, + actionTypeId: '.gen-ai', + isEnabledKnowledgeBase: true, + model: 'test_model', + isOssModel: false, + durationMs: 8077, + toolsInvoked: { + KnowledgeBaseRetrievalTool: 2, + NaturalLanguageESQLTool: 1, + CustomTool: 3, + }, + }); + }); +}); diff --git a/x-pack/packages/kbn-langchain/server/tracers/telemetry/telemetry_tracer.ts b/x-pack/packages/kbn-langchain/server/tracers/telemetry/telemetry_tracer.ts new file mode 100644 index 000000000000..7031e638c1fa --- /dev/null +++ b/x-pack/packages/kbn-langchain/server/tracers/telemetry/telemetry_tracer.ts @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BaseCallbackHandlerInput } from '@langchain/core/callbacks/base'; +import type { Run } from 'langsmith/schemas'; +import { BaseTracer } from '@langchain/core/tracers/base'; +import { AnalyticsServiceSetup, Logger } from '@kbn/core/server'; + +export interface TelemetryParams { + assistantStreamingEnabled: boolean; + actionTypeId: string; + isEnabledKnowledgeBase: boolean; + eventType: string; + model?: string; +} +export interface LangChainTracerFields extends BaseCallbackHandlerInput { + elasticTools: string[]; + telemetry: AnalyticsServiceSetup; + telemetryParams: TelemetryParams; + totalTools: number; +} +interface ToolRunStep { + action: { + tool: string; + }; +} +/** + * TelemetryTracer is a tracer that uses event based telemetry to track LangChain events. + */ +export class TelemetryTracer extends BaseTracer implements LangChainTracerFields { + name = 'telemetry_tracer'; + logger: Logger; + elasticTools: string[]; + telemetry: AnalyticsServiceSetup; + telemetryParams: TelemetryParams; + totalTools: number; + constructor(fields: LangChainTracerFields, logger: Logger) { + super(fields); + this.logger = logger.get('telemetryTracer'); + this.elasticTools = fields.elasticTools; + this.telemetry = fields.telemetry; + this.telemetryParams = fields.telemetryParams; + this.totalTools = fields.totalTools; + } + + async onChainEnd(run: Run): Promise { + if (!run.parent_run_id) { + const { eventType, ...telemetryParams } = this.telemetryParams; + const toolsInvoked = + run?.outputs && run?.outputs.steps.length + ? run.outputs.steps.reduce((acc: { [k: string]: number }, event: ToolRunStep | never) => { + if ('action' in event && event?.action?.tool) { + if (this.elasticTools.includes(event.action.tool)) { + return { + ...acc, + ...(event.action.tool in acc + ? { [event.action.tool]: acc[event.action.tool] + 1 } + : { [event.action.tool]: 1 }), + }; + } else { + // Custom tool names are user data, so we strip them out + return { + ...acc, + ...('CustomTool' in acc + ? { CustomTool: acc.CustomTool + 1 } + : { CustomTool: 1 }), + }; + } + } + return acc; + }, {}) + : {}; + const telemetryValue = { + ...telemetryParams, + durationMs: (run.end_time ?? 0) - (run.start_time ?? 0), + toolsInvoked, + ...(telemetryParams.actionTypeId === '.gen-ai' + ? { isOssModel: run.inputs.isOssModel } + : {}), + }; + this.logger.debug( + () => `Invoke ${eventType} telemetry:\n${JSON.stringify(telemetryValue, null, 2)}` + ); + this.telemetry.reportEvent(eventType, telemetryValue); + } + } + + // everything below is required for type only + protected async persistRun(_run: Run): Promise {} +} diff --git a/x-pack/packages/ml/random_sampler_utils/src/random_sampler_wrapper.ts b/x-pack/packages/ml/random_sampler_utils/src/random_sampler_wrapper.ts index 5054833ac7dd..39d26509422a 100644 --- a/x-pack/packages/ml/random_sampler_utils/src/random_sampler_wrapper.ts +++ b/x-pack/packages/ml/random_sampler_utils/src/random_sampler_wrapper.ts @@ -69,7 +69,6 @@ export const createRandomSamplerWrapper = (options: RandomSamplerOptions) => { return { [aggName]: { - // @ts-expect-error `random_sampler` is not yet part of `AggregationsAggregationContainer` random_sampler: { probability, ...(options.seed ? { seed: options.seed } : {}), 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 7519fea5f99f..193acb63f845 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 @@ -55,6 +55,7 @@ export function useAlertsHistory({ http, instanceId, }: Props): UseAlertsHistory { + const enabled = !!featureIds.length; const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ queryKey: ['useAlertsHistory'], queryFn: async ({ signal }) => { @@ -71,10 +72,11 @@ export function useAlertsHistory({ }); }, refetchOnWindowFocus: false, + enabled, }); return { data: isInitialLoading ? EMPTY_ALERTS_HISTORY : data ?? EMPTY_ALERTS_HISTORY, - isLoading: isInitialLoading || isLoading || isRefetching, + isLoading: enabled && (isInitialLoading || isLoading || isRefetching), isSuccess, isError, }; diff --git a/x-pack/packages/observability/observability_utils/hooks/use_abortable_async.ts b/x-pack/packages/observability/observability_utils/hooks/use_abortable_async.ts index 433ca877b0f6..477d765ef7a7 100644 --- a/x-pack/packages/observability/observability_utils/hooks/use_abortable_async.ts +++ b/x-pack/packages/observability/observability_utils/hooks/use_abortable_async.ts @@ -54,7 +54,9 @@ export function useAbortableAsync( }) .catch((err) => { setValue(undefined); - setError(err); + if (!controller.signal.aborted) { + setError(err); + } }) .finally(() => setLoading(false)); } else { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_context/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_context/index.test.tsx index fb8eccd4b7f8..a82bf7d6c432 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_context/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_context/index.test.tsx @@ -65,6 +65,8 @@ const ContextWrapper: FC> = ({ children }) => ( }, ]} setSelectedIlmPhaseOptions={jest.fn()} + defaultStartTime="now-7d" + defaultEndTime="now" > {children} diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_context/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_context/index.tsx index 762efef424a1..876ff528e75f 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_context/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_context/index.tsx @@ -41,6 +41,8 @@ export interface DataQualityProviderProps { ilmPhases: string[]; selectedIlmPhaseOptions: EuiComboBoxOptionOption[]; setSelectedIlmPhaseOptions: (options: EuiComboBoxOptionOption[]) => void; + defaultStartTime: string; + defaultEndTime: string; } const DataQualityContext = React.createContext(undefined); @@ -67,6 +69,8 @@ export const DataQualityProvider: React.FC { const value = useMemo( () => ({ @@ -90,6 +94,8 @@ export const DataQualityProvider: React.FC {children} @@ -159,6 +161,8 @@ describe('useIlmExplain', () => { }, ]} setSelectedIlmPhaseOptions={jest.fn()} + defaultStartTime={'now-7d'} + defaultEndTime={'now'} > {children} diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_stats/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_stats/index.test.tsx index 061bbb5aa682..ae4ee9a7bd2c 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_stats/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_stats/index.test.tsx @@ -69,6 +69,8 @@ const ContextWrapper: FC> = ({ children }) => ( }, ]} setSelectedIlmPhaseOptions={jest.fn()} + defaultStartTime={'now-7d'} + defaultEndTime={'now'} > {children} @@ -119,6 +121,8 @@ const ContextWrapperILMNotAvailable: FC> = ({ childre }, ]} setSelectedIlmPhaseOptions={jest.fn()} + defaultStartTime={'now-7d'} + defaultEndTime={'now'} > {children} diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/index.test.tsx index f303d614bce0..cd9ddec6dffb 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/index.test.tsx @@ -403,10 +403,9 @@ describe('CheckAll', () => { // simulate the wall clock advancing for (let i = 0; i < totalIndexNames + 1; i++) { - act(() => { + await act(async () => { jest.advanceTimersByTime(1000 * 10); }); - await waitFor(() => {}); } }); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/hooks/use_stored_pattern_results/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/hooks/use_stored_pattern_results/index.test.tsx index d58bf3af39d5..5f90890eea69 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/hooks/use_stored_pattern_results/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/hooks/use_stored_pattern_results/index.test.tsx @@ -11,6 +11,10 @@ import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; import { getHistoricalResultStub } from '../../../../stub/get_historical_result_stub'; import { useStoredPatternResults } from '.'; +const startTime = 'now-7d'; +const endTime = 'now'; +const isILMAvailable = true; + describe('useStoredPatternResults', () => { const httpFetch = jest.fn(); const mockToasts = notificationServiceMock.createStartContract().toasts; @@ -21,7 +25,16 @@ describe('useStoredPatternResults', () => { describe('when patterns are empty', () => { it('should return an empty array and not call getStorageResults', () => { - const { result } = renderHook(() => useStoredPatternResults([], mockToasts, httpFetch)); + const { result } = renderHook(() => + useStoredPatternResults({ + patterns: [], + toasts: mockToasts, + httpFetch, + isILMAvailable, + startTime, + endTime, + }) + ); expect(result.current).toEqual([]); expect(httpFetch).not.toHaveBeenCalled(); @@ -45,7 +58,14 @@ describe('useStoredPatternResults', () => { }); const { result, waitFor } = renderHook(() => - useStoredPatternResults(patterns, mockToasts, httpFetch) + useStoredPatternResults({ + patterns, + toasts: mockToasts, + httpFetch, + isILMAvailable, + startTime, + endTime, + }) ); await waitFor(() => result.current.length > 0); @@ -104,5 +124,63 @@ describe('useStoredPatternResults', () => { }, ]); }); + + describe('when isILMAvailable is false', () => { + it('should call getStorageResults with startDate and endDate', async () => { + const patterns = ['pattern1-*', 'pattern2-*']; + + httpFetch.mockImplementation((path: string) => { + if (path === '/internal/ecs_data_quality_dashboard/results_latest/pattern1-*') { + return Promise.resolve([getHistoricalResultStub('pattern1-index1')]); + } + + if (path === '/internal/ecs_data_quality_dashboard/results_latest/pattern2-*') { + return Promise.resolve([getHistoricalResultStub('pattern2-index1')]); + } + + return Promise.reject(new Error('Invalid path')); + }); + + const { result, waitFor } = renderHook(() => + useStoredPatternResults({ + patterns, + toasts: mockToasts, + httpFetch, + isILMAvailable: false, + startTime, + endTime, + }) + ); + + await waitFor(() => result.current.length > 0); + + expect(httpFetch).toHaveBeenCalledTimes(2); + + expect(httpFetch).toHaveBeenCalledWith( + '/internal/ecs_data_quality_dashboard/results_latest/pattern1-*', + { + method: 'GET', + signal: expect.any(AbortSignal), + version: '1', + query: { + startDate: startTime, + endDate: endTime, + }, + } + ); + expect(httpFetch).toHaveBeenCalledWith( + '/internal/ecs_data_quality_dashboard/results_latest/pattern2-*', + { + method: 'GET', + signal: expect.any(AbortSignal), + version: '1', + query: { + startDate: startTime, + endDate: endTime, + }, + } + ); + }); + }); }); }); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/hooks/use_stored_pattern_results/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/hooks/use_stored_pattern_results/index.tsx index 17334c4b4a58..b92b36218c07 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/hooks/use_stored_pattern_results/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/hooks/use_stored_pattern_results/index.tsx @@ -10,13 +10,34 @@ import { HttpHandler } from '@kbn/core-http-browser'; import { isEmpty } from 'lodash/fp'; import { DataQualityCheckResult } from '../../../../types'; -import { formatResultFromStorage, getStorageResults } from '../../utils/storage'; +import { + GetStorageResultsOpts, + formatResultFromStorage, + getStorageResults, +} from '../../utils/storage'; -export const useStoredPatternResults = ( - patterns: string[], - toasts: IToasts, - httpFetch: HttpHandler -) => { +export interface UseStoredPatternResultsOpts { + patterns: string[]; + toasts: IToasts; + httpFetch: HttpHandler; + isILMAvailable: boolean; + startTime: string; + endTime: string; +} + +export type UseStoredPatternResultsReturnValue = Array<{ + pattern: string; + results: Record; +}>; + +export const useStoredPatternResults = ({ + patterns, + toasts, + httpFetch, + isILMAvailable, + startTime, + endTime, +}: UseStoredPatternResultsOpts): UseStoredPatternResultsReturnValue => { const [storedPatternResults, setStoredPatternResults] = useState< Array<{ pattern: string; results: Record }> >([]); @@ -28,8 +49,20 @@ export const useStoredPatternResults = ( const abortController = new AbortController(); const fetchStoredPatternResults = async () => { - const requests = patterns.map((pattern) => - getStorageResults({ pattern, httpFetch, abortController, toasts }).then((results = []) => ({ + const requests = patterns.map(async (pattern) => { + const getStorageResultsOpts: GetStorageResultsOpts = { + pattern, + httpFetch, + abortController, + toasts, + }; + + if (!isILMAvailable) { + getStorageResultsOpts.startTime = startTime; + getStorageResultsOpts.endTime = endTime; + } + + return getStorageResults(getStorageResultsOpts).then((results) => ({ pattern, results: Object.fromEntries( results.map((storageResult) => [ @@ -37,8 +70,8 @@ export const useStoredPatternResults = ( formatResultFromStorage({ storageResult, pattern }), ]) ), - })) - ); + })); + }); const patternResults = await Promise.all(requests); if (patternResults?.length) { @@ -47,7 +80,7 @@ export const useStoredPatternResults = ( }; fetchStoredPatternResults(); - }, [httpFetch, patterns, toasts]); + }, [endTime, httpFetch, isILMAvailable, patterns, startTime, toasts]); return storedPatternResults; }; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/index.test.tsx index bff3c3dd54f1..7dc74731d66d 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/index.test.tsx @@ -35,6 +35,8 @@ describe('useResultsRollup', () => { const patterns = ['auditbeat-*', 'packetbeat-*']; const isILMAvailable = true; + const startTime = 'now-7d'; + const endTime = 'now'; const useStoredPatternResultsMock = useStoredPatternResults as jest.Mock; @@ -52,6 +54,8 @@ describe('useResultsRollup', () => { patterns, isILMAvailable, telemetryEvents: mockTelemetryEvents, + startTime, + endTime, }) ); @@ -94,10 +98,19 @@ describe('useResultsRollup', () => { patterns: ['auditbeat-*'], isILMAvailable, telemetryEvents: mockTelemetryEvents, + startTime, + endTime, }) ); - expect(useStoredPatternResultsMock).toHaveBeenCalledWith(['auditbeat-*'], toasts, httpFetch); + expect(useStoredPatternResultsMock).toHaveBeenCalledWith({ + patterns: ['auditbeat-*'], + toasts, + httpFetch, + isILMAvailable, + startTime, + endTime, + }); expect(result.current.patternRollups).toEqual({ 'auditbeat-*': { @@ -119,6 +132,8 @@ describe('useResultsRollup', () => { patterns, isILMAvailable, telemetryEvents: mockTelemetryEvents, + startTime, + endTime, }) ); @@ -144,6 +159,8 @@ describe('useResultsRollup', () => { patterns, isILMAvailable, telemetryEvents: mockTelemetryEvents, + startTime, + endTime, }) ); @@ -180,6 +197,8 @@ describe('useResultsRollup', () => { patterns, isILMAvailable, telemetryEvents: mockTelemetryEvents, + startTime, + endTime, }) ); @@ -369,6 +388,8 @@ describe('useResultsRollup', () => { patterns, isILMAvailable: false, telemetryEvents: mockTelemetryEvents, + startTime, + endTime, }) ); @@ -532,6 +553,8 @@ describe('useResultsRollup', () => { patterns, isILMAvailable, telemetryEvents: mockTelemetryEvents, + startTime, + endTime, }) ); @@ -592,6 +615,8 @@ describe('useResultsRollup', () => { patterns, isILMAvailable, telemetryEvents: mockTelemetryEvents, + startTime, + endTime, }) ); @@ -654,6 +679,8 @@ describe('useResultsRollup', () => { patterns: ['packetbeat-*', 'auditbeat-*'], isILMAvailable, telemetryEvents: mockTelemetryEvents, + startTime, + endTime, }) ); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/index.tsx index d95f1d1b7f20..bfed849e373d 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/index.tsx @@ -40,6 +40,8 @@ interface Props { httpFetch: HttpHandler; telemetryEvents: TelemetryEvents; isILMAvailable: boolean; + startTime: string; + endTime: string; } export const useResultsRollup = ({ httpFetch, @@ -47,11 +49,20 @@ export const useResultsRollup = ({ patterns, isILMAvailable, telemetryEvents, + startTime, + endTime, }: Props): UseResultsRollupReturnValue => { const [patternIndexNames, setPatternIndexNames] = useState>({}); const [patternRollups, setPatternRollups] = useState>({}); - const storedPatternsResults = useStoredPatternResults(patterns, toasts, httpFetch); + const storedPatternsResults = useStoredPatternResults({ + httpFetch, + patterns, + toasts, + isILMAvailable, + startTime, + endTime, + }); useEffect(() => { if (!isEmpty(storedPatternsResults)) { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.test.ts index 9f315d65c01d..b43954e73f6f 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.test.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.test.ts @@ -200,4 +200,26 @@ describe('getStorageResults', () => { expect(toasts.addError).toHaveBeenCalledWith('test-error', { title: expect.any(String) }); expect(results).toEqual([]); }); + + it('should provide stad and end date', async () => { + await getStorageResults({ + httpFetch: fetch, + abortController: new AbortController(), + pattern: 'auditbeat-*', + toasts, + startTime: 'now-7d', + endTime: 'now', + }); + + expect(fetch).toHaveBeenCalledWith( + '/internal/ecs_data_quality_dashboard/results_latest/auditbeat-*', + expect.objectContaining({ + method: 'GET', + query: { + startDate: 'now-7d', + endDate: 'now', + }, + }) + ); + }); }); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.ts index e4a5c43d5b4a..7fc339c085be 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { HttpHandler } from '@kbn/core-http-browser'; +import { HttpFetchQuery, HttpHandler } from '@kbn/core-http-browser'; import { IToasts } from '@kbn/core-notifications-browser'; import { @@ -131,23 +131,40 @@ export async function postStorageResult({ } } +export interface GetStorageResultsOpts { + pattern: string; + httpFetch: HttpHandler; + toasts: IToasts; + abortController: AbortController; + startTime?: string; + endTime?: string; +} + export async function getStorageResults({ pattern, httpFetch, toasts, abortController, -}: { - pattern: string; - httpFetch: HttpHandler; - toasts: IToasts; - abortController: AbortController; -}): Promise { + startTime, + endTime, +}: GetStorageResultsOpts): Promise { try { const route = GET_INDEX_RESULTS_LATEST.replace('{pattern}', pattern); + + const query: HttpFetchQuery = {}; + + if (startTime) { + query.startDate = startTime; + } + if (endTime) { + query.endDate = endTime; + } + const results = await httpFetch(route, { method: 'GET', signal: abortController.signal, version: INTERNAL_API_VERSION, + ...(Object.keys(query).length > 0 ? { query } : {}), }); return results; } catch (err) { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.test.tsx index 90e5dba08d4d..f925a67ea3d3 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.test.tsx @@ -67,6 +67,8 @@ describe('DataQualityPanel', () => { setLastChecked={jest.fn()} baseTheme={DARK_THEME} toasts={toasts} + defaultStartTime={'now-7d'} + defaultEndTime={'now'} /> ); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.tsx index b6d2736d7e17..9b9cbdefb667 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.tsx @@ -46,6 +46,8 @@ interface Props { setLastChecked: (lastChecked: string) => void; startDate?: string | null; theme?: PartialTheme; + defaultStartTime: string; + defaultEndTime: string; } const defaultSelectedIlmPhaseOptions: EuiComboBoxOptionOption[] = ilmPhaseOptionsStatic.filter( @@ -71,6 +73,8 @@ const DataQualityPanelComponent: React.FC = ({ setLastChecked, startDate, theme, + defaultStartTime, + defaultEndTime, }) => { const [selectedIlmPhaseOptions, setSelectedIlmPhaseOptions] = useState( defaultSelectedIlmPhaseOptions @@ -109,6 +113,8 @@ const DataQualityPanelComponent: React.FC = ({ toasts, isILMAvailable, telemetryEvents, + startTime: defaultStartTime, + endTime: defaultEndTime, }); const indicesCheckHookReturnValue = useIndicesCheck({ @@ -137,6 +143,8 @@ const DataQualityPanelComponent: React.FC = ({ ilmPhases={ilmPhases} selectedIlmPhaseOptions={selectedIlmPhaseOptions} setSelectedIlmPhaseOptions={setSelectedIlmPhaseOptions} + defaultStartTime={defaultStartTime} + defaultEndTime={defaultEndTime} > diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/test_providers.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/test_providers.tsx index 17b73f1e6dcd..e0220d26e869 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/test_providers.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/test_providers.tsx @@ -135,6 +135,8 @@ const TestDataQualityProvidersComponent: React.FC ilmPhases, selectedIlmPhaseOptions, setSelectedIlmPhaseOptions, + defaultStartTime, + defaultEndTime, } = getMergedDataQualityContextProps(dataQualityContextProps); const mergedResultsRollupContextProps = @@ -162,6 +164,8 @@ const TestDataQualityProvidersComponent: React.FC ilmPhases={ilmPhases} selectedIlmPhaseOptions={selectedIlmPhaseOptions} setSelectedIlmPhaseOptions={setSelectedIlmPhaseOptions} + defaultStartTime={defaultStartTime} + defaultEndTime={defaultEndTime} > { isPopoverOpen: false, }; + private getPrivilegeCopy = (privilege: string): { label?: string; icon?: string } => { + switch (privilege) { + case 'all': + return { + icon: 'documentEdit', + label: i18n.translate( + 'xpack.security.management.editRole.changeAllPrivileges.allSelectionLabel', + { + defaultMessage: 'Grant full access for all', + } + ), + }; + case 'read': + return { + icon: 'glasses', + label: i18n.translate( + 'xpack.security.management.editRole.changeAllPrivileges.readSelectionLabel', + { + defaultMessage: 'Grant read access for all', + } + ), + }; + case 'none': + return { + icon: 'trash', + label: i18n.translate( + 'xpack.security.management.editRole.changeAllPrivileges.noneSelectionLabel', + { + defaultMessage: 'Revoke access to all', + } + ), + }; + default: + return {}; + } + }; + public render() { const button = ( { ); const items = this.props.privileges.map((privilege) => { + const { icon, label } = this.getPrivilegeCopy(privilege.id); return ( { @@ -65,21 +104,24 @@ export class ChangeAllPrivilegesControl extends Component { }} disabled={this.props.disabled} > - {_.upperFirst(privilege.id)} + {label} ); }); items.push( { this.onSelectPrivilege(NO_PRIVILEGE_VALUE); }} disabled={this.props.disabled} + // @ts-expect-error leaving this here so that when https://github.com/elastic/eui/issues/8123 is fixed we remove this comment + css={({ euiTheme }) => ({ color: euiTheme.colors.danger })} > - {_.upperFirst(NO_PRIVILEGE_VALUE)} + {this.getPrivilegeCopy(NO_PRIVILEGE_VALUE).label} ); diff --git a/x-pack/packages/security/ui_components/src/kibana_privilege_table/feature_table.test.tsx b/x-pack/packages/security/ui_components/src/kibana_privilege_table/feature_table.test.tsx index 2c858e7bb6ff..2ed172a49ad8 100644 --- a/x-pack/packages/security/ui_components/src/kibana_privilege_table/feature_table.test.tsx +++ b/x-pack/packages/security/ui_components/src/kibana_privilege_table/feature_table.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiAccordion, EuiIconTip } from '@elastic/eui'; +import { EuiAccordion, EuiIconTip, EuiThemeProvider } from '@elastic/eui'; import React from 'react'; import type { KibanaFeature, SubFeatureConfig } from '@kbn/features-plugin/public'; @@ -47,16 +47,18 @@ const setup = (config: TestConfig) => { const onChange = jest.fn(); const onChangeAll = jest.fn(); const wrapper = mountWithIntl( - + + + ); const displayedPrivileges = config.calculateDisplayedPrivileges diff --git a/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap b/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap index 94bc911557c2..e8b3cc7bebe2 100644 --- a/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap +++ b/x-pack/plugins/actions/server/integration_tests/__snapshots__/connector_types.test.ts.snap @@ -2251,6 +2251,78 @@ Object { ], "type": "string", }, + "getIncidentJson": Object { + "flags": Object { + "default": null, + "error": [Function], + "presence": "optional", + }, + "matches": Array [ + Object { + "schema": Object { + "flags": Object { + "error": [Function], + }, + "rules": Array [ + Object { + "args": Object { + "method": [Function], + }, + "name": "custom", + }, + ], + "type": "string", + }, + }, + Object { + "schema": Object { + "allow": Array [ + null, + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + ], + "type": "alternatives", + }, + "getIncidentMethod": Object { + "flags": Object { + "default": "get", + "error": [Function], + "presence": "optional", + }, + "matches": Array [ + Object { + "schema": Object { + "allow": Array [ + "get", + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + Object { + "schema": Object { + "allow": Array [ + "post", + ], + "flags": Object { + "error": [Function], + "only": true, + }, + "type": "any", + }, + }, + ], + "type": "alternatives", + }, "getIncidentResponseExternalTitleKey": Object { "flags": Object { "error": [Function], diff --git a/x-pack/plugins/actions/server/lib/axios_utils.test.ts b/x-pack/plugins/actions/server/lib/axios_utils.test.ts index bee09a90ed27..b7bb7548b905 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.test.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.test.ts @@ -577,4 +577,12 @@ describe('throwIfResponseIsNotValid', () => { }) ).not.toThrow(); }); + + test('it does NOT throw if HTTP status code is 204 even if the content type is not supported', () => { + expect(() => + throwIfResponseIsNotValid({ + res: { ...res, status: 204, headers: { ['content-type']: 'text/html' } }, + }) + ).not.toThrow(); + }); }); diff --git a/x-pack/plugins/actions/server/lib/axios_utils.ts b/x-pack/plugins/actions/server/lib/axios_utils.ts index 254ad1a36f6e..78abebf48022 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.ts @@ -137,6 +137,16 @@ export const throwIfResponseIsNotValid = ({ const requiredContentType = 'application/json'; const contentType = res.headers['content-type'] ?? 'undefined'; const data = res.data; + const statusCode = res.status; + + /** + * Some external services may return a 204 + * status code but with unsupported content type like text/html. + * To avoid throwing on valid requests we return. + */ + if (statusCode === 204) { + return; + } /** * Check that the content-type of the response is application/json. diff --git a/x-pack/plugins/aiops/public/components/log_categorization/categorize_field_actions.ts b/x-pack/plugins/aiops/public/components/log_categorization/categorize_field_actions.ts index 10c6311d065d..e5e6ede86355 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/categorize_field_actions.ts +++ b/x-pack/plugins/aiops/public/components/log_categorization/categorize_field_actions.ts @@ -10,7 +10,6 @@ import { createAction } from '@kbn/ui-actions-plugin/public'; import type { CoreStart } from '@kbn/core/public'; import { ACTION_CATEGORIZE_FIELD, type CategorizeFieldContext } from '@kbn/ml-ui-actions'; import type { AiopsPluginStartDeps } from '../../types'; -import { showCategorizeFlyout } from './show_flyout'; export const createCategorizeFieldAction = (coreStart: CoreStart, plugins: AiopsPluginStartDeps) => createAction({ @@ -25,6 +24,7 @@ export const createCategorizeFieldAction = (coreStart: CoreStart, plugins: Aiops }, execute: async (context: CategorizeFieldContext) => { const { field, dataView, originatingApp, additionalFilter } = context; + const { showCategorizeFlyout } = await import('./show_flyout'); showCategorizeFlyout(field, dataView, coreStart, plugins, originatingApp, additionalFilter); }, }); diff --git a/x-pack/plugins/aiops/public/components/log_categorization/index.ts b/x-pack/plugins/aiops/public/components/log_categorization/index.ts index ace01d4f0338..748a0f848642 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/index.ts +++ b/x-pack/plugins/aiops/public/components/log_categorization/index.ts @@ -7,7 +7,6 @@ export type { LogCategorizationAppStateProps } from './log_categorization_app_state'; import { LogCategorizationAppState } from './log_categorization_app_state'; -export { createCategorizeFieldAction } from './categorize_field_actions'; // required for dynamic import using React.lazy() // eslint-disable-next-line import/no-default-export diff --git a/x-pack/plugins/aiops/public/components/log_categorization/show_flyout.tsx b/x-pack/plugins/aiops/public/components/log_categorization/show_flyout.tsx index a97f4c7f7fe7..6dae21c36222 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/show_flyout.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/show_flyout.tsx @@ -36,7 +36,7 @@ export async function showCategorizeFlyout( ): Promise { const { overlays, application, i18n } = coreStart; - return new Promise(async (resolve, reject) => { + return new Promise((resolve, reject) => { try { const onFlyoutClose = () => { flyoutSession.close(); diff --git a/x-pack/plugins/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx b/x-pack/plugins/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx index 2ce1a46780db..5f7ff6ff67f7 100644 --- a/x-pack/plugins/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx +++ b/x-pack/plugins/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx @@ -15,13 +15,6 @@ import type { DataView } from '@kbn/data-views-plugin/common'; import { DATA_VIEW_SAVED_OBJECT_TYPE } from '@kbn/data-views-plugin/common'; import type { ReactEmbeddableFactory } from '@kbn/embeddable-plugin/public'; import { i18n } from '@kbn/i18n'; -import { - apiHasExecutionContext, - fetch$, - initializeTimeRange, - initializeTitles, - useBatchedPublishingSubjects, -} from '@kbn/presentation-publishing'; import fastIsEqual from 'fast-deep-equal'; import { cloneDeep } from 'lodash'; @@ -61,6 +54,14 @@ export const getChangePointChartEmbeddableFactory = ( return serializedState; }, buildEmbeddable: async (state, buildApi, uuid, parentApi) => { + const { + apiHasExecutionContext, + fetch$, + initializeTimeRange, + initializeTitles, + useBatchedPublishingSubjects, + } = await import('@kbn/presentation-publishing'); + const [coreStart, pluginStart] = await getStartServices(); const { diff --git a/x-pack/plugins/aiops/public/embeddables/pattern_analysis/embeddable_pattern_analysis_factory.tsx b/x-pack/plugins/aiops/public/embeddables/pattern_analysis/embeddable_pattern_analysis_factory.tsx index d84043ea5f63..e0017668b338 100644 --- a/x-pack/plugins/aiops/public/embeddables/pattern_analysis/embeddable_pattern_analysis_factory.tsx +++ b/x-pack/plugins/aiops/public/embeddables/pattern_analysis/embeddable_pattern_analysis_factory.tsx @@ -15,13 +15,6 @@ import type { DataView } from '@kbn/data-views-plugin/common'; import { DATA_VIEW_SAVED_OBJECT_TYPE } from '@kbn/data-views-plugin/common'; import type { ReactEmbeddableFactory } from '@kbn/embeddable-plugin/public'; import { i18n } from '@kbn/i18n'; -import { - apiHasExecutionContext, - fetch$, - initializeTimeRange, - initializeTitles, - useBatchedPublishingSubjects, -} from '@kbn/presentation-publishing'; import fastIsEqual from 'fast-deep-equal'; import { cloneDeep } from 'lodash'; import React, { useMemo } from 'react'; @@ -58,6 +51,14 @@ export const getPatternAnalysisEmbeddableFactory = ( return serializedState; }, buildEmbeddable: async (state, buildApi, uuid, parentApi) => { + const { + apiHasExecutionContext, + fetch$, + initializeTimeRange, + initializeTitles, + useBatchedPublishingSubjects, + } = await import('@kbn/presentation-publishing'); + const [coreStart, pluginStart] = await getStartServices(); const { diff --git a/x-pack/plugins/aiops/public/plugin.tsx b/x-pack/plugins/aiops/public/plugin.tsx index ceb378b0f29b..5863ea03b307 100755 --- a/x-pack/plugins/aiops/public/plugin.tsx +++ b/x-pack/plugins/aiops/public/plugin.tsx @@ -8,15 +8,18 @@ import type { CoreStart, Plugin } from '@kbn/core/public'; import { type CoreSetup } from '@kbn/core/public'; import { firstValueFrom } from 'rxjs'; -import { dynamic } from '@kbn/shared-ux-utility'; import { getChangePointDetectionComponent } from './shared_components'; +import { LogCategorizationForDiscover as PatternAnalysisComponent } from './shared_lazy_components'; import type { AiopsPluginSetup, AiopsPluginSetupDeps, AiopsPluginStart, AiopsPluginStartDeps, } from './types'; +import { registerEmbeddables } from './embeddables'; +import { registerAiopsUiActions } from './ui_actions'; +import { registerChangePointChartsAttachment } from './cases/register_change_point_charts_attachment'; export type AiopsCoreSetup = CoreSetup; @@ -27,20 +30,8 @@ export class AiopsPlugin core: AiopsCoreSetup, { embeddable, cases, licensing, uiActions }: AiopsPluginSetupDeps ) { - Promise.all([ - firstValueFrom(licensing.license$), - import('./embeddables'), - import('./ui_actions'), - import('./cases/register_change_point_charts_attachment'), - core.getStartServices(), - ]).then( - ([ - license, - { registerEmbeddables }, - { registerAiopsUiActions }, - { registerChangePointChartsAttachment }, - [coreStart, pluginStart], - ]) => { + Promise.all([firstValueFrom(licensing.license$), core.getStartServices()]).then( + ([license, [coreStart, pluginStart]]) => { const { canUseAiops } = coreStart.application.capabilities.ml; if (license.hasAtLeast('platinum') && canUseAiops) { @@ -69,12 +60,7 @@ export class AiopsPlugin ); return getPatternAnalysisAvailable(plugins.licensing); }, - PatternAnalysisComponent: dynamic( - async () => - import( - './components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover_wrapper' - ) - ), + PatternAnalysisComponent, }; } diff --git a/x-pack/plugins/aiops/public/shared_lazy_components.tsx b/x-pack/plugins/aiops/public/shared_lazy_components.tsx index fe9e31f14659..b34efdd6bff0 100644 --- a/x-pack/plugins/aiops/public/shared_lazy_components.tsx +++ b/x-pack/plugins/aiops/public/shared_lazy_components.tsx @@ -12,6 +12,7 @@ import { EuiErrorBoundary, EuiSkeletonText } from '@elastic/eui'; import type { LogRateAnalysisAppStateProps } from './components/log_rate_analysis'; import type { LogRateAnalysisContentWrapperProps } from './components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper'; import type { LogCategorizationAppStateProps } from './components/log_categorization'; +import type { LogCategorizationEmbeddableWrapperProps } from './components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover_wrapper'; import type { ChangePointDetectionAppStateProps } from './components/change_point_detection'; const LogRateAnalysisAppStateLazy = React.lazy(() => import('./components/log_rate_analysis')); @@ -58,6 +59,25 @@ export const LogCategorization: FC = (props) => ); +const LogCategorizationForDiscoverLazy = React.lazy( + () => + import( + './components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover_wrapper' + ) +); + +/** + * Lazy-wrapped LogCategorizationForDiscover React component + * @param {LogCategorizationEmbeddableWrapperProps} props - properties specifying the data on which to run the analysis. + */ +export const LogCategorizationForDiscover: FC = ( + props +) => ( + + + +); + const ChangePointDetectionLazy = React.lazy(() => import('./components/change_point_detection')); /** * Lazy-wrapped ChangePointDetectionAppStateProps React component diff --git a/x-pack/plugins/aiops/public/ui_actions/change_point_action_context.ts b/x-pack/plugins/aiops/public/ui_actions/change_point_action_context.ts index a4307b69d3fa..3bf2eee92256 100644 --- a/x-pack/plugins/aiops/public/ui_actions/change_point_action_context.ts +++ b/x-pack/plugins/aiops/public/ui_actions/change_point_action_context.ts @@ -6,7 +6,8 @@ */ import { isPopulatedObject } from '@kbn/ml-is-populated-object'; -import { apiIsOfType, type EmbeddableApiContext } from '@kbn/presentation-publishing'; +import type { EmbeddableApiContext } from '@kbn/presentation-publishing'; +import { apiIsOfType } from '@kbn/presentation-publishing/interfaces/has_type'; import { EMBEDDABLE_CHANGE_POINT_CHART_TYPE } from '@kbn/aiops-change-point-detection/constants'; import type { ChangePointEmbeddableApi } from '../embeddables/change_point_chart/types'; diff --git a/x-pack/plugins/aiops/public/ui_actions/index.ts b/x-pack/plugins/aiops/public/ui_actions/index.ts index 6081541c448e..b0b39083aabd 100644 --- a/x-pack/plugins/aiops/public/ui_actions/index.ts +++ b/x-pack/plugins/aiops/public/ui_actions/index.ts @@ -16,7 +16,7 @@ import type { CoreStart } from '@kbn/core/public'; import { createAddChangePointChartAction } from './create_change_point_chart'; import { createOpenChangePointInMlAppAction } from './open_change_point_ml'; import type { AiopsPluginStartDeps } from '../types'; -import { createCategorizeFieldAction } from '../components/log_categorization'; +import { createCategorizeFieldAction } from '../components/log_categorization/categorize_field_actions'; import { createAddPatternAnalysisEmbeddableAction } from './create_pattern_analysis_action'; import { createAddLogRateAnalysisEmbeddableAction } from './create_log_rate_analysis_actions'; diff --git a/x-pack/plugins/aiops/public/ui_actions/open_change_point_ml.tsx b/x-pack/plugins/aiops/public/ui_actions/open_change_point_ml.tsx index 8d2e4f1bbd08..3d52d34a72b8 100644 --- a/x-pack/plugins/aiops/public/ui_actions/open_change_point_ml.tsx +++ b/x-pack/plugins/aiops/public/ui_actions/open_change_point_ml.tsx @@ -10,17 +10,17 @@ import { IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; import { i18n } from '@kbn/i18n'; import type { CoreStart } from '@kbn/core/public'; import type { TimeRange } from '@kbn/es-query'; -import { apiHasParentApi, apiPublishesTimeRange } from '@kbn/presentation-publishing'; import type { ChangePointEmbeddableApi } from '../embeddables/change_point_chart/types'; import type { AiopsPluginStartDeps } from '../types'; import type { ChangePointChartActionContext } from './change_point_action_context'; -import { isChangePointChartEmbeddableContext } from './change_point_action_context'; export const OPEN_CHANGE_POINT_IN_ML_APP_ACTION = 'openChangePointInMlAppAction'; -export const getEmbeddableTimeRange = ( +const getEmbeddableTimeRange = async ( embeddable: ChangePointEmbeddableApi -): TimeRange | undefined => { +): Promise => { + const { apiHasParentApi, apiPublishesTimeRange } = await import('@kbn/presentation-publishing'); + let timeRange = embeddable.timeRange$?.getValue(); if (!timeRange && apiHasParentApi(embeddable) && apiPublishesTimeRange(embeddable.parentApi)) { @@ -45,6 +45,7 @@ export function createOpenChangePointInMlAppAction( defaultMessage: 'Open in AIOps Labs', }), async getHref(context): Promise { + const { isChangePointChartEmbeddableContext } = await import('./change_point_action_context'); if (!isChangePointChartEmbeddableContext(context)) { throw new IncompatibleActionError(); } @@ -57,7 +58,7 @@ export function createOpenChangePointInMlAppAction( page: 'aiops/change_point_detection', pageState: { index: dataViewId.getValue(), - timeRange: getEmbeddableTimeRange(context.embeddable), + timeRange: await getEmbeddableTimeRange(context.embeddable), fieldConfigs: [ { fn: fn.getValue(), @@ -69,6 +70,7 @@ export function createOpenChangePointInMlAppAction( }); }, async execute(context) { + const { isChangePointChartEmbeddableContext } = await import('./change_point_action_context'); if (!isChangePointChartEmbeddableContext(context)) { throw new IncompatibleActionError(); } @@ -78,6 +80,7 @@ export function createOpenChangePointInMlAppAction( } }, async isCompatible(context) { + const { isChangePointChartEmbeddableContext } = await import('./change_point_action_context'); return isChangePointChartEmbeddableContext(context); }, }; diff --git a/x-pack/plugins/alerting/server/saved_objects/index.ts b/x-pack/plugins/alerting/server/saved_objects/index.ts index 8e76f28ff7fb..8f11020ee628 100644 --- a/x-pack/plugins/alerting/server/saved_objects/index.ts +++ b/x-pack/plugins/alerting/server/saved_objects/index.ts @@ -217,6 +217,11 @@ export function setupSavedObjects( // Encrypted attributes encryptedSavedObjects.registerType({ type: RULE_SAVED_OBJECT_TYPE, + /** + * We disable enforcing random SO IDs for the rule SO + * to allow users creating rules with a predefined ID. + */ + enforceRandomId: false, attributesToEncrypt: new Set(RuleAttributesToEncrypt), attributesToIncludeInAAD: new Set(RuleAttributesIncludedInAAD), }); diff --git a/x-pack/plugins/canvas/public/state/actions/elements.js b/x-pack/plugins/canvas/public/state/actions/elements.js index 57b7da1ce1fe..dc21cf1b8f2b 100644 --- a/x-pack/plugins/canvas/public/state/actions/elements.js +++ b/x-pack/plugins/canvas/public/state/actions/elements.js @@ -65,9 +65,12 @@ function getBareElement(el, includeId = false) { export const elementLayer = createAction('elementLayer'); -export const setMultiplePositions = createAction('setMultiplePosition', (repositionedElements) => ({ - repositionedElements, -})); +export const setMultiplePositions = createAction( + 'setMultiplePositions', + (repositionedElements) => ({ + repositionedElements, + }) +); export const flushContext = createAction('flushContext'); export const flushContextAfterIndex = createAction('flushContextAfterIndex'); diff --git a/x-pack/plugins/cases/public/components/add_comment/index.test.tsx b/x-pack/plugins/cases/public/components/add_comment/index.test.tsx index 68cf0c8a1e2b..5664151aa6df 100644 --- a/x-pack/plugins/cases/public/components/add_comment/index.test.tsx +++ b/x-pack/plugins/cases/public/components/add_comment/index.test.tsx @@ -21,12 +21,13 @@ import { CasesTimelineIntegrationProvider } from '../timeline_context'; import { timelineIntegrationMock } from '../__mock__/timeline'; import type { CaseAttachmentWithoutOwner } from '../../types'; import type { AppMockRenderer } from '../../common/mock'; +import { useCreateAttachments } from '../../containers/use_create_attachments'; -jest.mock('../../containers/api', () => ({ - createAttachments: jest.fn(), -})); +jest.mock('../../containers/use_create_attachments'); -const createAttachmentsMock = createAttachments as jest.Mock; +const useCreateAttachmentsMock = useCreateAttachments as jest.Mock; + +const createAttachmentsMock = jest.fn().mockImplementation(() => defaultResponse); const onCommentSaving = jest.fn(); const onCommentPosted = jest.fn(); @@ -58,7 +59,10 @@ describe('AddComment ', () => { beforeEach(() => { jest.clearAllMocks(); appMockRender = createAppMockRenderer(); - createAttachmentsMock.mockImplementation(() => defaultResponse); + useCreateAttachmentsMock.mockReturnValue({ + isLoading: false, + mutate: createAttachmentsMock, + }); }); afterEach(() => { @@ -72,6 +76,11 @@ describe('AddComment ', () => { }); it('should render spinner and disable submit when loading', async () => { + useCreateAttachmentsMock.mockReturnValue({ + isLoading: true, + mutateAsync: createAttachmentsMock, + }); + appMockRender.render(); fireEvent.change(screen.getByLabelText('caseComment'), { @@ -109,16 +118,19 @@ describe('AddComment ', () => { await waitFor(() => expect(onCommentSaving).toBeCalled()); await waitFor(() => - expect(createAttachmentsMock).toBeCalledWith({ - caseId: addCommentProps.caseId, - attachments: [ - { - comment: sampleData.comment, - owner: SECURITY_SOLUTION_OWNER, - type: AttachmentType.user, - }, - ], - }) + expect(createAttachmentsMock).toBeCalledWith( + { + caseId: addCommentProps.caseId, + attachments: [ + { + comment: sampleData.comment, + type: AttachmentType.user, + }, + ], + caseOwner: SECURITY_SOLUTION_OWNER, + }, + { onSuccess: expect.any(Function) } + ) ); await waitFor(() => { expect(screen.getByTestId('euiMarkdownEditorTextArea')).toHaveTextContent(''); @@ -258,16 +270,19 @@ describe('draft comment ', () => { await waitFor(() => { expect(onCommentSaving).toBeCalled(); - expect(createAttachmentsMock).toBeCalledWith({ - caseId: addCommentProps.caseId, - attachments: [ - { - comment: sampleData.comment, - owner: SECURITY_SOLUTION_OWNER, - type: AttachmentType.user, - }, - ], - }); + expect(createAttachmentsMock).toBeCalledWith( + { + caseId: addCommentProps.caseId, + attachments: [ + { + comment: sampleData.comment, + type: AttachmentType.user, + }, + ], + caseOwner: SECURITY_SOLUTION_OWNER, + }, + { onSuccess: expect.any(Function) } + ); }); await waitFor(() => { diff --git a/x-pack/plugins/cases/public/components/create/index.test.tsx b/x-pack/plugins/cases/public/components/create/index.test.tsx index bb519b1f6f77..37e817d00f33 100644 --- a/x-pack/plugins/cases/public/components/create/index.test.tsx +++ b/x-pack/plugins/cases/public/components/create/index.test.tsx @@ -172,6 +172,8 @@ describe('CreateCase case', () => { await user.click(screen.getByTestId('create-case-submit')); - expect(defaultProps.onSuccess).toHaveBeenCalled(); + await waitFor(() => { + expect(defaultProps.onSuccess).toHaveBeenCalled(); + }); }); }); diff --git a/x-pack/plugins/cases/public/components/links/index.tsx b/x-pack/plugins/cases/public/components/links/index.tsx index f1e8ca5cdb4a..9b610db63ed1 100644 --- a/x-pack/plugins/cases/public/components/links/index.tsx +++ b/x-pack/plugins/cases/public/components/links/index.tsx @@ -12,7 +12,7 @@ import { useCaseViewNavigation, useConfigureCasesNavigation } from '../../common import * as i18n from './translations'; export interface CasesNavigation { - href: K extends 'configurable' ? (arg: T) => string : string; + href?: K extends 'configurable' ? (arg: T) => string : string; onClick: K extends 'configurable' ? (arg: T, arg2: React.MouseEvent | MouseEvent) => Promise | void : (arg: T) => Promise | void; diff --git a/x-pack/plugins/cases/public/components/use_push_to_service/index.test.tsx b/x-pack/plugins/cases/public/components/use_push_to_service/index.test.tsx index fccca04bb278..75c2694f8947 100644 --- a/x-pack/plugins/cases/public/components/use_push_to_service/index.test.tsx +++ b/x-pack/plugins/cases/public/components/use_push_to_service/index.test.tsx @@ -13,7 +13,6 @@ import { usePushToService } from '.'; import { noPushCasesPermissions, readCasesPermissions, TestProviders } from '../../common/mock'; import { usePostPushToService } from '../../containers/use_post_push_to_service'; import { actionLicenses } from '../../containers/mock'; -import { CLOSED_CASE_PUSH_ERROR_ID } from './callout/types'; import { useGetActionLicense } from '../../containers/use_get_action_license'; import { getCaseConnectorsMockResponse } from '../../common/mock/connectors'; import { useRefreshCaseViewPage } from '../case_view/use_on_refresh_case_view_page'; @@ -182,27 +181,6 @@ describe('usePushToService', () => { expect(result.current.hasErrorMessages).toBe(true); }); - it('Displays message when case is closed', async () => { - const { result } = renderHook< - React.PropsWithChildren, - ReturnUsePushToService - >( - () => - usePushToService({ - ...defaultArgs, - caseStatus: CaseStatuses.closed, - }), - { - wrapper: ({ children }) => {children}, - } - ); - - const errorsMsg = result.current.errorsMsg; - expect(errorsMsg).toHaveLength(1); - expect(errorsMsg[0].id).toEqual(CLOSED_CASE_PUSH_ERROR_ID); - expect(result.current.hasErrorMessages).toBe(true); - }); - it('should not call pushCaseToExternalService when the selected connector is none', async () => { const { result } = renderHook< React.PropsWithChildren, @@ -460,7 +438,7 @@ describe('usePushToService', () => { const { result } = renderHook< React.PropsWithChildren, ReturnUsePushToService - >(() => usePushToService({ ...defaultArgs, caseStatus: CaseStatuses.closed }), { + >(() => usePushToService({ ...defaultArgs, isValidConnector: false }), { wrapper: ({ children }) => {children}, }); diff --git a/x-pack/plugins/cases/public/components/use_push_to_service/index.tsx b/x-pack/plugins/cases/public/components/use_push_to_service/index.tsx index 63a016964651..465e48bddade 100644 --- a/x-pack/plugins/cases/public/components/use_push_to_service/index.tsx +++ b/x-pack/plugins/cases/public/components/use_push_to_service/index.tsx @@ -13,10 +13,8 @@ import { getKibanaConfigError, getConnectorMissingInfo, getDeletedConnectorError, - getCaseClosedInfo, } from './helpers'; import type { CaseConnector } from '../../../common/types/domain'; -import { CaseStatuses } from '../../../common/types/domain'; import type { ErrorMessage } from './callout/types'; import { useRefreshCaseViewPage } from '../case_view/use_on_refresh_case_view_page'; import { useGetActionLicense } from '../../containers/use_get_action_license'; @@ -44,7 +42,6 @@ export interface ReturnUsePushToService { export const usePushToService = ({ caseId, - caseStatus, caseConnectors, connector, isValidConnector, @@ -108,14 +105,9 @@ export const usePushToService = ({ return [getDeletedConnectorError()]; } - if (caseStatus === CaseStatuses.closed) { - return [getCaseClosedInfo()]; - } - return errors; }, [ actionLicense, - caseStatus, connector.id, hasLicenseError, isValidConnector, diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/alert_event.test.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/alert_event.test.tsx index 60d5759de6e2..d060f1d9d71a 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/alert_event.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/alert_event.test.tsx @@ -47,10 +47,38 @@ describe('Alert events', () => { expect(wrapper.text()).toBe('added an alert from Awesome rule'); }); - it('does NOT render the link when the rule id is null', async () => { + it('renders the link when onClick is provided but href is not valid', async () => { const wrapper = mount( - + + + ); + + expect( + wrapper.find(`[data-test-subj="alert-rule-link-action-id-1"]`).first().exists() + ).toBeTruthy(); + }); + + it('renders the link when href is valid but onClick is not available', async () => { + const wrapper = mount( + + + + ); + + expect( + wrapper.find(`[data-test-subj="alert-rule-link-action-id-1"]`).first().exists() + ).toBeTruthy(); + }); + + it('does NOT render the link when the href and onclick are invalid but it shows the rule name', async () => { + const wrapper = mount( + + ); @@ -61,10 +89,10 @@ describe('Alert events', () => { expect(wrapper.text()).toBe('added an alert from Awesome rule'); }); - it('does NOT render the link when the href is invalid but it shows the rule name', async () => { + it('does NOT render the link when the rule id is null', async () => { const wrapper = mount( - + ); @@ -131,9 +159,28 @@ describe('Alert events', () => { expect(result.getByTestId('alert-rule-link-action-id-1')).toHaveTextContent('Awesome rule'); }); - it('does NOT render the link when the rule id is null', async () => { + it('renders the link when onClick is provided but href is not valid', async () => { const result = appMock.render( - + + ); + expect(result.getByTestId('alert-rule-link-action-id-1')).toHaveTextContent('Awesome rule'); + }); + + it('renders the link when href is valid but onClick is not available', async () => { + const result = appMock.render( + + ); + expect(result.getByTestId('alert-rule-link-action-id-1')).toHaveTextContent('Awesome rule'); + }); + + it('does NOT render the link when the href and onclick are invalid but it shows the rule name', async () => { + const result = appMock.render( + ); expect(result.getByTestId('multiple-alerts-user-action-action-id-1')).toHaveTextContent( @@ -142,9 +189,9 @@ describe('Alert events', () => { expect(result.queryByTestId('alert-rule-link-action-id-1')).toBeFalsy(); }); - it('does NOT render the link when the href is invalid but it shows the rule name', async () => { + it('does NOT render the link when the rule id is null', async () => { const result = appMock.render( - + ); expect(result.getByTestId('multiple-alerts-user-action-action-id-1')).toHaveTextContent( diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/alert_event.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/alert_event.tsx index 42e5e6b9d442..a8ffbb987a02 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/alert_event.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/alert_event.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { memo, useCallback } from 'react'; +import React, { memo, useCallback, useMemo } from 'react'; import { isEmpty } from 'lodash'; import { EuiLoadingSpinner } from '@elastic/eui'; @@ -38,12 +38,18 @@ const RuleLink: React.FC = memo( const ruleDetailsHref = getRuleDetailsHref?.(ruleId); const finalRuleName = ruleName ?? i18n.UNKNOWN_RULE; + const isValidLink = useMemo(() => { + if (!onRuleDetailsClick && !ruleDetailsHref) { + return false; + } + return !isEmpty(ruleId); + }, [onRuleDetailsClick, ruleDetailsHref, ruleId]); if (loadingAlertData) { return ; } - if (!isEmpty(ruleId) && ruleDetailsHref != null) { + if (isValidLink) { return ( { +// FLAKY: https://github.com/elastic/kibana/issues/195672 +describe.skip('DeleteAttachmentConfirmationModal', () => { let appMock: AppMockRenderer; const props = { title: 'My title', diff --git a/x-pack/plugins/cases/server/client/cases/push.ts b/x-pack/plugins/cases/server/client/cases/push.ts index 85d853f82590..6d4561c7b511 100644 --- a/x-pack/plugins/cases/server/client/cases/push.ts +++ b/x-pack/plugins/cases/server/client/cases/push.ts @@ -140,12 +140,6 @@ export const push = async ( operation: Operations.pushCase, }); - if (theCase?.status === CaseStatuses.closed) { - throw Boom.conflict( - `The ${theCase.title} case is closed. Pushing a closed case is not allowed.` - ); - } - const alertsInfo = getAlertInfoFromComments(theCase?.comments); const alerts = await getAlerts(alertsInfo, clientArgs); const profiles = await getProfiles(theCase, securityStartPlugin); diff --git a/x-pack/plugins/cases/server/saved_object_types/cases/model_versions.test.ts b/x-pack/plugins/cases/server/saved_object_types/cases/model_versions.test.ts index 8520fd9673d3..2c301709ca5c 100644 --- a/x-pack/plugins/cases/server/saved_object_types/cases/model_versions.test.ts +++ b/x-pack/plugins/cases/server/saved_object_types/cases/model_versions.test.ts @@ -10,51 +10,49 @@ import { modelVersion1 } from './model_versions'; describe('Model versions', () => { describe('1', () => { it('returns the model version correctly', () => { - expect(modelVersion1).toMatchInlineSnapshot(` - Object { - "changes": Array [ - Object { - "addedMappings": Object { - "customFields": Object { - "properties": Object { - "key": Object { - "type": "keyword", - }, - "type": Object { - "type": "keyword", - }, - "value": Object { - "fields": Object { - "boolean": Object { - "ignore_malformed": true, - "type": "boolean", - }, - "date": Object { - "ignore_malformed": true, - "type": "date", - }, - "ip": Object { - "ignore_malformed": true, - "type": "ip", - }, - "number": Object { - "ignore_malformed": true, - "type": "long", - }, - "string": Object { - "type": "text", - }, + expect(modelVersion1.changes).toMatchInlineSnapshot(` + Array [ + Object { + "addedMappings": Object { + "customFields": Object { + "properties": Object { + "key": Object { + "type": "keyword", + }, + "type": Object { + "type": "keyword", + }, + "value": Object { + "fields": Object { + "boolean": Object { + "ignore_malformed": true, + "type": "boolean", + }, + "date": Object { + "ignore_malformed": true, + "type": "date", + }, + "ip": Object { + "ignore_malformed": true, + "type": "ip", + }, + "number": Object { + "ignore_malformed": true, + "type": "long", + }, + "string": Object { + "type": "text", }, - "type": "keyword", }, + "type": "keyword", }, - "type": "nested", }, + "type": "nested", }, - "type": "mappings_addition", }, - ], - } + "type": "mappings_addition", + }, + ] `); }); }); diff --git a/x-pack/plugins/cases/server/saved_object_types/cases/model_versions.ts b/x-pack/plugins/cases/server/saved_object_types/cases/model_versions.ts index 56806e7dec60..7d46789a3b79 100644 --- a/x-pack/plugins/cases/server/saved_object_types/cases/model_versions.ts +++ b/x-pack/plugins/cases/server/saved_object_types/cases/model_versions.ts @@ -6,6 +6,7 @@ */ import type { SavedObjectsModelVersion } from '@kbn/core-saved-objects-server'; +import { casesSchemaV1 } from './schemas'; /** * Adds custom fields to the cases SO. @@ -54,4 +55,7 @@ export const modelVersion1: SavedObjectsModelVersion = { }, }, ], + schemas: { + forwardCompatibility: casesSchemaV1.extends({}, { unknowns: 'ignore' }), + }, }; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/utils/recall/types.ts b/x-pack/plugins/cases/server/saved_object_types/cases/schemas/index.ts similarity index 61% rename from x-pack/plugins/observability_solution/observability_ai_assistant/server/utils/recall/types.ts rename to x-pack/plugins/cases/server/saved_object_types/cases/schemas/index.ts index 3774df64c1ee..85d9239f72db 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/utils/recall/types.ts +++ b/x-pack/plugins/cases/server/saved_object_types/cases/schemas/index.ts @@ -5,6 +5,6 @@ * 2.0. */ -import type { RecalledEntry } from '../../service/knowledge_base_service'; +export * from './latest'; -export type RetrievedSuggestion = Omit; +export { casesSchema as casesSchemaV1 } from './v1'; diff --git a/x-pack/plugins/search_indices/public/components/start/types.ts b/x-pack/plugins/cases/server/saved_object_types/cases/schemas/latest.ts similarity index 56% rename from x-pack/plugins/search_indices/public/components/start/types.ts rename to x-pack/plugins/cases/server/saved_object_types/cases/schemas/latest.ts index 4c0235ec515f..25300c97a6d2 100644 --- a/x-pack/plugins/search_indices/public/components/start/types.ts +++ b/x-pack/plugins/cases/server/saved_object_types/cases/schemas/latest.ts @@ -5,10 +5,4 @@ * 2.0. */ -import type { AvailableLanguages } from '../../code_examples'; - -export interface CreateIndexFormState { - indexName: string; - defaultIndexName: string; - codingLanguage: AvailableLanguages; -} +export * from './v1'; diff --git a/x-pack/plugins/cases/server/saved_object_types/cases/schemas/v1.ts b/x-pack/plugins/cases/server/saved_object_types/cases/schemas/v1.ts new file mode 100644 index 000000000000..1a6bb0a8cdd8 --- /dev/null +++ b/x-pack/plugins/cases/server/saved_object_types/cases/schemas/v1.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; + +const UserSchema = schema.object({ + email: schema.nullable(schema.string()), + full_name: schema.nullable(schema.string()), + username: schema.nullable(schema.string()), + profile_uid: schema.nullable(schema.string()), +}); + +const UserProfileSchema = schema.object({ uid: schema.string() }); + +const ConnectorSchema = schema.object({ + name: schema.string(), + type: schema.string(), + fields: schema.arrayOf(schema.object({ key: schema.string(), value: schema.string() })), +}); + +const ExternalServiceSchema = schema.object({ + connector_name: schema.string(), + external_id: schema.string(), + external_title: schema.string(), + external_url: schema.string(), + pushed_at: schema.string(), + pushed_by: UserSchema, +}); + +const SettingsSchema = schema.object({ syncAlerts: schema.boolean() }); + +const CustomFieldsSchema = schema.arrayOf( + schema.object({ + key: schema.string(), + type: schema.string(), + value: schema.nullable(schema.any()), + }) +); + +export const casesSchema = schema.object({ + assignees: schema.arrayOf(UserProfileSchema), + category: schema.maybe(schema.nullable(schema.string())), + closed_at: schema.nullable(schema.string()), + closed_by: schema.nullable(UserSchema), + created_at: schema.string(), + created_by: UserSchema, + connector: ConnectorSchema, + customFields: schema.maybe(schema.nullable(CustomFieldsSchema)), + description: schema.string(), + duration: schema.nullable(schema.number()), + external_service: schema.nullable(ExternalServiceSchema), + owner: schema.string(), + settings: SettingsSchema, + severity: schema.oneOf([ + schema.literal(10), + schema.literal(20), + schema.literal(30), + schema.literal(40), + ]), + status: schema.oneOf([schema.literal(0), schema.literal(10), schema.literal(20)]), + tags: schema.arrayOf(schema.string()), + title: schema.string(), + total_alerts: schema.number(), + total_comments: schema.number(), + updated_at: schema.nullable(schema.string()), + updated_by: schema.nullable(UserSchema), +}); diff --git a/x-pack/plugins/cloud/server/routes/elasticsearch_routes.ts b/x-pack/plugins/cloud/server/routes/elasticsearch_routes.ts index 5cdc2f90559c..d3a5c4bebf30 100644 --- a/x-pack/plugins/cloud/server/routes/elasticsearch_routes.ts +++ b/x-pack/plugins/cloud/server/routes/elasticsearch_routes.ts @@ -24,12 +24,24 @@ export function defineRoutes({ path: ELASTICSEARCH_CONFIG_ROUTE, access: 'internal', }) - .addVersion({ version: '1', validate: {} }, async (context, request, response) => { - const body: ElasticsearchConfigType = { - elasticsearch_url: elasticsearchUrl, - }; - return response.ok({ - body, - }); - }); + .addVersion( + { + version: '1', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: {}, + }, + async (context, request, response) => { + const body: ElasticsearchConfigType = { + elasticsearch_url: elasticsearchUrl, + }; + return response.ok({ + body, + }); + } + ); } diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credentials_form/gcp_credential_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credentials_form/gcp_credential_form.tsx index 638af9617e00..7d6d42c70e76 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credentials_form/gcp_credential_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credentials_form/gcp_credential_form.tsx @@ -500,7 +500,7 @@ export const GcpCredentialsForm = ({ diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts index be08984c16db..e31ce74ee945 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts @@ -151,7 +151,7 @@ export const generateFindingHit = (finding: CspFinding) => { }; }; -const getFindingsBsearchResponse = (findings: CspFinding[]) => { +const getFindingsSearchResponse = (findings: CspFinding[]) => { const buckets = findings.reduce( (acc, finding) => { if (finding.result.evaluation === 'failed') { @@ -174,28 +174,26 @@ const getFindingsBsearchResponse = (findings: CspFinding[]) => { ); return { - id: 0, - result: { - rawResponse: { - took: 1, - timed_out: false, - _shards: { - total: 1, - successful: 1, - skipped: 0, - failed: 0, - }, - hits: { - total: findings.length, - max_score: null, - hits: findings.map(generateFindingHit), - }, - aggregations: { - count: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets, - }, + id: '1', + rawResponse: { + took: 1, + timed_out: false, + _shards: { + total: 1, + successful: 1, + skipped: 0, + failed: 0, + }, + hits: { + total: findings.length, + max_score: null, + hits: findings.map(generateFindingHit), + }, + aggregations: { + count: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets, }, }, isPartial: false, @@ -214,8 +212,8 @@ export const rulesGetStatesHandler = http.get( } ); -export const bsearchFindingsHandler = (findings: CspFinding[]) => - http.post('internal/bsearch', async ({ request }) => { +export const searchFindingsHandler = (findings: CspFinding[]) => + http.post('internal/search', async ({ request }) => { const jsonRequest = (await request.json()) as Partial; const filter = jsonRequest?.query?.bool?.filter; @@ -233,7 +231,7 @@ export const bsearchFindingsHandler = (findings: CspFinding[]) => return finding.rule.section === termValue; }); - return HttpResponse.json(getFindingsBsearchResponse(filteredFindings)); + return HttpResponse.json(getFindingsSearchResponse(filteredFindings)); } const hasRuleSectionFilter = @@ -244,7 +242,7 @@ export const bsearchFindingsHandler = (findings: CspFinding[]) => return finding.rule.section === filter?.[0]?.match_phrase?.['rule.section']; }); - return HttpResponse.json(getFindingsBsearchResponse(filteredFindings)); + return HttpResponse.json(getFindingsSearchResponse(filteredFindings)); } const hasResultEvaluationFilter = @@ -255,8 +253,8 @@ export const bsearchFindingsHandler = (findings: CspFinding[]) => return finding.result.evaluation === filter?.[0]?.match_phrase?.['result.evaluation']; }); - return HttpResponse.json(getFindingsBsearchResponse(filteredFindings)); + return HttpResponse.json(getFindingsSearchResponse(filteredFindings)); } - return HttpResponse.json(getFindingsBsearchResponse(findings)); + return HttpResponse.json(getFindingsSearchResponse(findings)); }); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.test.tsx index 8f1a8f159ced..cd834f460635 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.test.tsx @@ -20,7 +20,7 @@ import { FilterManager } from '@kbn/data-plugin/public'; import { CspClientPluginStartDeps } from '@kbn/cloud-security-posture'; import * as statusHandlers from '../../../server/routes/status/status.handlers.mock'; import { - bsearchFindingsHandler, + searchFindingsHandler, generateCspFinding, generateMultipleCspFindings, rulesGetStatesHandler, @@ -58,7 +58,7 @@ describe('', () => { const finding2 = generateCspFinding('0004', 'passed'); server.use(statusHandlers.notInstalledHasMisconfigurationsFindingsHandler); - server.use(bsearchFindingsHandler([finding1, finding2])); + server.use(searchFindingsHandler([finding1, finding2])); renderFindingsPage(); // Loading while checking the status API and fetching the findings @@ -89,7 +89,7 @@ describe('', () => { const finding2 = generateCspFinding('0002', 'passed'); server.use(statusHandlers.indexedHandler); - server.use(bsearchFindingsHandler([finding1, finding2])); + server.use(searchFindingsHandler([finding1, finding2])); renderFindingsPage(); // Loading while checking the status API @@ -118,7 +118,7 @@ describe('', () => { const finding2 = generateCspFinding('0002', 'passed'); server.use(statusHandlers.indexedHandler); - server.use(bsearchFindingsHandler([finding1, finding2])); + server.use(searchFindingsHandler([finding1, finding2])); renderFindingsPage(); @@ -148,7 +148,7 @@ describe('', () => { const finding2 = generateCspFinding('0002', 'passed'); server.use(statusHandlers.indexedHandler); - server.use(bsearchFindingsHandler([finding1, finding2])); + server.use(searchFindingsHandler([finding1, finding2])); renderFindingsPage(); @@ -180,7 +180,7 @@ describe('', () => { const finding2 = generateCspFinding('0002', 'passed'); server.use(statusHandlers.indexedHandler); - server.use(bsearchFindingsHandler([finding1, finding2])); + server.use(searchFindingsHandler([finding1, finding2])); renderFindingsPage(); @@ -259,7 +259,7 @@ describe('', () => { }; server.use(statusHandlers.indexedHandler); - server.use(bsearchFindingsHandler([finding1, finding2])); + server.use(searchFindingsHandler([finding1, finding2])); renderFindingsPage(mockDependenciesWithFilter); @@ -286,7 +286,7 @@ describe('', () => { it('renders the distribution bar', async () => { server.use(statusHandlers.indexedHandler); server.use( - bsearchFindingsHandler( + searchFindingsHandler( generateMultipleCspFindings({ count: 10, failedCount: 3, @@ -316,7 +316,7 @@ describe('', () => { it('filters by passed findings when clicking on the passed findings button', async () => { server.use(statusHandlers.indexedHandler); server.use( - bsearchFindingsHandler( + searchFindingsHandler( generateMultipleCspFindings({ count: 2, failedCount: 1, @@ -352,7 +352,7 @@ describe('', () => { it('filters by failed findings when clicking on the failed findings button', async () => { server.use(statusHandlers.indexedHandler); server.use( - bsearchFindingsHandler( + searchFindingsHandler( generateMultipleCspFindings({ count: 2, failedCount: 1, diff --git a/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts b/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts index 86ec3e3108f2..1c5480f339a6 100644 --- a/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts +++ b/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts @@ -28,7 +28,7 @@ jest.mock('rxjs', () => { ...actual, lastValueFrom: async (source: Promise) => { const value = await source; - return value.result; + return value; }, }; }); @@ -97,7 +97,7 @@ export const getMockServerDependencies = () => { search: { ...getMockDependencies().data.search, search: async ({ params }: { params: any }) => { - const response = await fetch(`${MOCK_SERVER_BASE_URL}/internal/bsearch`, { + const response = await fetch(`${MOCK_SERVER_BASE_URL}/internal/search`, { method: 'POST', headers: { 'Content-Type': 'application/json', 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 14b55541a1ba..b72cb27088ed 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 @@ -44,8 +44,10 @@ export const defineBulkActionCspBenchmarkRulesRoute = (router: CspRouter) => .post({ access: 'internal', path: CSP_BENCHMARK_RULES_BULK_ACTION_ROUTE_PATH, - options: { - tags: ['access:cloud-security-posture-all'], + security: { + authz: { + requiredPrivileges: ['cloud-security-posture-all'], + }, }, }) .addVersion( diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/find.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/find.ts index 738a8774266d..a205ad95419d 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/find.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/find.ts @@ -25,8 +25,10 @@ export const defineFindCspBenchmarkRuleRoute = (router: CspRouter) => .get({ access: 'internal', path: FIND_CSP_BENCHMARK_RULE_ROUTE_PATH, - options: { - tags: ['access:cloud-security-posture-read'], + security: { + authz: { + requiredPrivileges: ['cloud-security-posture-read'], + }, }, }) .addVersion( diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/get_states/get_states.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/get_states/get_states.ts index 31ef05abc7cc..a737313ffc66 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/get_states/get_states.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/get_states/get_states.ts @@ -16,8 +16,10 @@ export const defineGetCspBenchmarkRulesStatesRoute = (router: CspRouter) => .get({ access: 'internal', path: CSP_GET_BENCHMARK_RULES_STATE_ROUTE_PATH, - options: { - tags: ['access:cloud-security-posture-read'], + security: { + authz: { + requiredPrivileges: ['cloud-security-posture-read'], + }, }, }) .addVersion( diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmarks/benchmarks.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmarks/benchmarks.ts index c3854b1dafb4..efbdedad3d3a 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmarks/benchmarks.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmarks/benchmarks.ts @@ -20,8 +20,10 @@ export const defineGetBenchmarksRoute = (router: CspRouter) => .get({ access: 'internal', path: BENCHMARKS_ROUTE_PATH, - options: { - tags: ['access:cloud-security-posture-read'], + security: { + authz: { + requiredPrivileges: ['cloud-security-posture-read'], + }, }, }) .addVersion( diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/compliance_dashboard.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/compliance_dashboard.ts index 851fa865566f..481433e1efd5 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/compliance_dashboard.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/compliance_dashboard.ts @@ -65,8 +65,10 @@ export const defineGetComplianceDashboardRoute = (router: CspRouter) => .get({ access: 'internal', path: STATS_ROUTE_PATH, - options: { - tags: ['access:cloud-security-posture-read'], + security: { + authz: { + requiredPrivileges: ['cloud-security-posture-read'], + }, }, }) .addVersion( diff --git a/x-pack/plugins/cloud_security_posture/server/routes/detection_engine/get_detection_engine_alerts_count_by_rule_tags.ts b/x-pack/plugins/cloud_security_posture/server/routes/detection_engine/get_detection_engine_alerts_count_by_rule_tags.ts index 6455b34707f7..38a9e356a144 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/detection_engine/get_detection_engine_alerts_count_by_rule_tags.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/detection_engine/get_detection_engine_alerts_count_by_rule_tags.ts @@ -53,8 +53,10 @@ export const defineGetDetectionEngineAlertsStatus = (router: CspRouter) => .get({ access: 'internal', path: GET_DETECTION_RULE_ALERTS_STATUS_PATH, - options: { - tags: ['access:cloud-security-posture-read'], + security: { + authz: { + requiredPrivileges: ['cloud-security-posture-read'], + }, }, }) .addVersion( diff --git a/x-pack/plugins/cloud_security_posture/server/routes/graph/route.ts b/x-pack/plugins/cloud_security_posture/server/routes/graph/route.ts index 9ff15c2be73e..9fb817b275a0 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/graph/route.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/graph/route.ts @@ -10,6 +10,7 @@ import { graphResponseSchema, } from '@kbn/cloud-security-posture-common/schema/graph/latest'; import { transformError } from '@kbn/securitysolution-es-utils'; +import type { GraphRequest } from '@kbn/cloud-security-posture-common/types/graph/v1'; import { GRAPH_ROUTE_PATH } from '../../../common/constants'; import { CspRouter } from '../../types'; import { getGraph as getGraphV1 } from './v1'; @@ -20,8 +21,10 @@ export const defineGraphRoute = (router: CspRouter) => access: 'internal', enableQueryVersion: true, path: GRAPH_ROUTE_PATH, - options: { - tags: ['access:cloud-security-posture-read'], + security: { + authz: { + requiredPrivileges: ['cloud-security-posture-read'], + }, }, }) .addVersion( @@ -37,26 +40,29 @@ export const defineGraphRoute = (router: CspRouter) => }, }, async (context, request, response) => { - const { actorIds, eventIds, start, end } = request.body.query; + const { nodesLimit, showUnknownTarget = false } = request.body; + const { eventIds, start, end, esQuery } = request.body.query as GraphRequest['query']; const cspContext = await context.csp; const spaceId = (await cspContext.spaces?.spacesService?.getActiveSpace(request))?.id; try { - const { nodes, edges } = await getGraphV1( - { + const resp = await getGraphV1({ + services: { logger: cspContext.logger, esClient: cspContext.esClient, }, - { - actorIds, + query: { eventIds, spaceId, start, end, - } - ); + esQuery, + }, + showUnknownTarget, + nodesLimit, + }); - return response.ok({ body: { nodes, edges } }); + return response.ok({ body: resp }); } catch (err) { const error = transformError(err); cspContext.logger.error(`Failed to fetch graph ${err}`); diff --git a/x-pack/plugins/cloud_security_posture/server/routes/graph/types.ts b/x-pack/plugins/cloud_security_posture/server/routes/graph/types.ts deleted file mode 100644 index ba32664da623..000000000000 --- a/x-pack/plugins/cloud_security_posture/server/routes/graph/types.ts +++ /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 type { - EdgeDataModel, - NodeDataModel, -} from '@kbn/cloud-security-posture-common/types/graph/latest'; -import type { Logger, IScopedClusterClient } from '@kbn/core/server'; -import type { Writable } from '@kbn/utility-types'; - -export interface GraphContextServices { - logger: Logger; - esClient: IScopedClusterClient; -} - -export interface GraphContext { - nodes: Array>; - edges: Array>; -} diff --git a/x-pack/plugins/cloud_security_posture/server/routes/graph/v1.ts b/x-pack/plugins/cloud_security_posture/server/routes/graph/v1.ts index 5102d153c190..b14a2ba3e06a 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/graph/v1.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/graph/v1.ts @@ -8,22 +8,27 @@ import { castArray } from 'lodash'; import { v4 as uuidv4 } from 'uuid'; import type { Logger, IScopedClusterClient } from '@kbn/core/server'; +import { ApiMessageCode } from '@kbn/cloud-security-posture-common/types/graph/latest'; import type { + Color, EdgeDataModel, - NodeDataModel, EntityNodeDataModel, - LabelNodeDataModel, + GraphRequest, + GraphResponse, GroupNodeDataModel, -} from '@kbn/cloud-security-posture-common/types/graph/latest'; + LabelNodeDataModel, + NodeDataModel, +} from '@kbn/cloud-security-posture-common/types/graph/v1'; import type { EsqlToRecords } from '@elastic/elasticsearch/lib/helpers'; import type { Writable } from '@kbn/utility-types'; -import type { GraphContextServices, GraphContext } from './types'; + +type EsQuery = GraphRequest['query']['esQuery']; interface GraphEdge { badge: number; - ips: string[]; - hosts: string[]; - users: string[]; + ips?: string[] | string; + hosts?: string[] | string; + users?: string[] | string; actorIds: string[] | string; action: string; targetIds: string[] | string; @@ -36,50 +41,75 @@ interface LabelEdges { target: string; } -export const getGraph = async ( - services: GraphContextServices, +interface GraphContextServices { + logger: Logger; + esClient: IScopedClusterClient; +} + +interface GetGraphParams { + services: GraphContextServices; query: { - actorIds: string[]; eventIds: string[]; spaceId?: string; start: string | number; end: string | number; - } -): Promise<{ - nodes: NodeDataModel[]; - edges: EdgeDataModel[]; -}> => { - const { esClient, logger } = services; - const { actorIds, eventIds, spaceId = 'default', start, end } = query; - - logger.trace( - `Fetching graph for [eventIds: ${eventIds.join(', ')}] [actorIds: ${actorIds.join( - ', ' - )}] in [spaceId: ${spaceId}]` - ); + esQuery?: EsQuery; + }; + showUnknownTarget: boolean; + nodesLimit?: number; +} - const results = await fetchGraph({ esClient, logger, start, end, eventIds, actorIds }); +export const getGraph = async ({ + services: { esClient, logger }, + query: { eventIds, spaceId = 'default', start, end, esQuery }, + showUnknownTarget, + nodesLimit, +}: GetGraphParams): Promise> => { + logger.trace(`Fetching graph for [eventIds: ${eventIds.join(', ')}] in [spaceId: ${spaceId}]`); + + const results = await fetchGraph({ + esClient, + showUnknownTarget, + logger, + start, + end, + eventIds, + esQuery, + }); // Convert results into set of nodes and edges - const graphContext = parseRecords(logger, results.records); - - return { nodes: graphContext.nodes, edges: graphContext.edges }; + return parseRecords(logger, results.records, nodesLimit); }; interface ParseContext { - nodesMap: Record; - edgesMap: Record; - edgeLabelsNodes: Record; - labelEdges: Record; + readonly nodesLimit?: number; + readonly nodesMap: Record; + readonly edgesMap: Record; + readonly edgeLabelsNodes: Record; + readonly labelEdges: Record; + readonly messages: ApiMessageCode[]; + readonly logger: Logger; } -const parseRecords = (logger: Logger, records: GraphEdge[]): GraphContext => { - const ctx: ParseContext = { nodesMap: {}, edgeLabelsNodes: {}, edgesMap: {}, labelEdges: {} }; +const parseRecords = ( + logger: Logger, + records: GraphEdge[], + nodesLimit?: number +): Pick => { + const ctx: ParseContext = { + nodesLimit, + logger, + nodesMap: {}, + edgeLabelsNodes: {}, + edgesMap: {}, + labelEdges: {}, + messages: [], + }; - logger.trace(`Parsing records [length: ${records.length}]`); + logger.trace(`Parsing records [length: ${records.length}] [nodesLimit: ${nodesLimit ?? 'none'}]`); - createNodes(logger, records, ctx); - createEdgesAndGroups(logger, ctx); + createNodes(records, ctx); + createEdgesAndGroups(ctx); logger.trace( `Parsed [nodes: ${Object.keys(ctx.nodesMap).length}, edges: ${ @@ -90,7 +120,11 @@ const parseRecords = (logger: Logger, records: GraphEdge[]): GraphContext => { // Sort groups to be first (fixes minor layout issue) const nodes = sortNodes(ctx.nodesMap); - return { nodes, edges: Object.values(ctx.edgesMap) }; + return { + nodes, + edges: Object.values(ctx.edgesMap), + messages: ctx.messages.length > 0 ? ctx.messages : undefined, + }; }; const fetchGraph = async ({ @@ -98,15 +132,17 @@ const fetchGraph = async ({ logger, start, end, - actorIds, eventIds, + showUnknownTarget, + esQuery, }: { esClient: IScopedClusterClient; logger: Logger; start: string | number; end: string | number; - actorIds: string[]; eventIds: string[]; + showUnknownTarget: boolean; + esQuery?: EsQuery; }): Promise> => { const query = `from logs-* | WHERE event.action IS NOT NULL AND actor.entity.id IS NOT NULL @@ -124,59 +160,84 @@ const fetchGraph = async ({ targetIds = target.entity.id, eventOutcome = event.outcome, isAlert -| LIMIT 1000`; +| LIMIT 1000 +| SORT isAlert DESC`; logger.trace(`Executing query [${query}]`); return await esClient.asCurrentUser.helpers .esql({ columnar: false, - filter: { - bool: { - must: [ + filter: buildDslFilter(eventIds, showUnknownTarget, start, end, esQuery), + query, + // @ts-ignore - types are not up to date + params: [...eventIds.map((id, idx) => ({ [`al_id${idx}`]: id }))], + }) + .toRecords(); +}; + +const buildDslFilter = ( + eventIds: string[], + showUnknownTarget: boolean, + start: string | number, + end: string | number, + esQuery?: EsQuery +) => ({ + bool: { + filter: [ + { + range: { + '@timestamp': { + gte: start, + lte: end, + }, + }, + }, + ...(showUnknownTarget + ? [] + : [ { - range: { - '@timestamp': { - gte: start, - lte: end, - }, + exists: { + field: 'target.entity.id', }, }, + ]), + { + bool: { + should: [ + ...(esQuery?.bool.filter?.length || + esQuery?.bool.must?.length || + esQuery?.bool.should?.length || + esQuery?.bool.must_not?.length + ? [esQuery] + : []), { - bool: { - should: [ - { - terms: { - 'event.id': eventIds, - }, - }, - { - terms: { - 'actor.entity.id': actorIds, - }, - }, - ], - minimum_should_match: 1, + terms: { + 'event.id': eventIds, }, }, ], + minimum_should_match: 1, }, }, - query, - // @ts-ignore - types are not up to date - params: [...eventIds.map((id, idx) => ({ [`al_id${idx}`]: id }))], - }) - .toRecords(); -}; + ], + }, +}); -const createNodes = ( - logger: Logger, - records: GraphEdge[], - context: Omit -) => { +const createNodes = (records: GraphEdge[], context: Omit) => { const { nodesMap, edgeLabelsNodes, labelEdges } = context; for (const record of records) { + if (context.nodesLimit !== undefined && Object.keys(nodesMap).length >= context.nodesLimit) { + context.logger.debug( + `Reached nodes limit [limit: ${context.nodesLimit}] [current: ${ + Object.keys(nodesMap).length + }]` + ); + context.messages.push(ApiMessageCode.ReachedNodesLimit); + break; + } + const { ips, hosts, users, actorIds, action, targetIds, isAlert, eventOutcome } = record; const actorIdsArray = castArray(actorIds); const targetIdsArray = castArray(targetIds); @@ -190,12 +251,6 @@ const createNodes = ( } }); - logger.trace( - `Parsing record [actorIds: ${actorIdsArray.join( - ', ' - )}, action: ${action}, targetIds: ${targetIdsArray.join(', ')}]` - ); - // Create entity nodes [...actorIdsArray, ...targetIdsArray].forEach((id) => { if (nodesMap[id] === undefined) { @@ -203,10 +258,13 @@ const createNodes = ( id, label: unknownTargets.includes(id) ? 'Unknown' : undefined, color: isAlert ? 'danger' : 'primary', - ...determineEntityNodeShape(id, ips ?? [], hosts ?? [], users ?? []), + ...determineEntityNodeShape( + id, + castArray(ips ?? []), + castArray(hosts ?? []), + castArray(users ?? []) + ), }; - - logger.trace(`Creating entity node [${id}]`); } }); @@ -226,8 +284,6 @@ const createNodes = ( shape: 'label', }; - logger.trace(`Creating label node [${labelNode.id}]`); - nodesMap[labelNode.id] = labelNode; edgeLabelsNodes[edgeId].push(labelNode.id); labelEdges[labelNode.id] = { source: actorId, target: targetId }; @@ -278,7 +334,7 @@ const sortNodes = (nodesMap: Record) => { return [...groupNodes, ...otherNodes]; }; -const createEdgesAndGroups = (logger: Logger, context: ParseContext) => { +const createEdgesAndGroups = (context: ParseContext) => { const { edgeLabelsNodes, edgesMap, nodesMap, labelEdges } = context; Object.entries(edgeLabelsNodes).forEach(([edgeId, edgeLabelsIds]) => { @@ -287,7 +343,6 @@ const createEdgesAndGroups = (logger: Logger, context: ParseContext) => { const edgeLabelId = edgeLabelsIds[0]; connectEntitiesAndLabelNode( - logger, edgesMap, nodesMap, labelEdges[edgeLabelId].source, @@ -300,44 +355,47 @@ const createEdgesAndGroups = (logger: Logger, context: ParseContext) => { shape: 'group', }; nodesMap[groupNode.id] = groupNode; + let groupEdgesColor: Color = 'primary'; + + edgeLabelsIds.forEach((edgeLabelId) => { + (nodesMap[edgeLabelId] as Writable).parentId = groupNode.id; + connectEntitiesAndLabelNode(edgesMap, nodesMap, groupNode.id, edgeLabelId, groupNode.id); + + if ((nodesMap[edgeLabelId] as LabelNodeDataModel).color === 'danger') { + groupEdgesColor = 'danger'; + } else if ( + (nodesMap[edgeLabelId] as LabelNodeDataModel).color === 'warning' && + groupEdgesColor !== 'danger' + ) { + // Use warning only if there's no danger color + groupEdgesColor = 'warning'; + } + }); connectEntitiesAndLabelNode( - logger, edgesMap, nodesMap, labelEdges[edgeLabelsIds[0]].source, groupNode.id, - labelEdges[edgeLabelsIds[0]].target + labelEdges[edgeLabelsIds[0]].target, + groupEdgesColor ); - - edgeLabelsIds.forEach((edgeLabelId) => { - (nodesMap[edgeLabelId] as Writable).parentId = groupNode.id; - connectEntitiesAndLabelNode( - logger, - edgesMap, - nodesMap, - groupNode.id, - edgeLabelId, - groupNode.id - ); - }); } }); }; const connectEntitiesAndLabelNode = ( - logger: Logger, edgesMap: Record, nodesMap: Record, sourceNodeId: string, labelNodeId: string, - targetNodeId: string + targetNodeId: string, + colorOverride?: Color ) => { [ - connectNodes(nodesMap, sourceNodeId, labelNodeId), - connectNodes(nodesMap, labelNodeId, targetNodeId), + connectNodes(nodesMap, sourceNodeId, labelNodeId, colorOverride), + connectNodes(nodesMap, labelNodeId, targetNodeId, colorOverride), ].forEach((edge) => { - logger.trace(`Connecting nodes [${edge.source} -> ${edge.target}]`); edgesMap[edge.id] = edge; }); }; @@ -345,7 +403,8 @@ const connectEntitiesAndLabelNode = ( const connectNodes = ( nodesMap: Record, sourceNodeId: string, - targetNodeId: string + targetNodeId: string, + colorOverride?: Color ): EdgeDataModel => { const sourceNode = nodesMap[sourceNodeId]; const targetNode = nodesMap[targetNodeId]; @@ -360,6 +419,6 @@ const connectNodes = ( id: `a(${sourceNodeId})-b(${targetNodeId})`, source: sourceNodeId, target: targetNodeId, - color, + color: colorOverride ?? color, }; }; diff --git a/x-pack/plugins/cloud_security_posture/server/routes/status/status.ts b/x-pack/plugins/cloud_security_posture/server/routes/status/status.ts index 4f5c84b936fb..066d0c936e27 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/status/status.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/status/status.ts @@ -437,8 +437,10 @@ export const defineGetCspStatusRoute = ( .get({ access: 'internal', path: STATUS_ROUTE_PATH, - options: { - tags: ['access:cloud-security-posture-read'], + security: { + authz: { + requiredPrivileges: ['cloud-security-posture-read'], + }, }, }) .addVersion( diff --git a/x-pack/plugins/cloud_security_posture/server/routes/vulnerabilities_dashboard/vulnerabilities_dashboard.ts b/x-pack/plugins/cloud_security_posture/server/routes/vulnerabilities_dashboard/vulnerabilities_dashboard.ts index f7de7f1be4b6..e336e6dbc0c0 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/vulnerabilities_dashboard/vulnerabilities_dashboard.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/vulnerabilities_dashboard/vulnerabilities_dashboard.ts @@ -20,8 +20,10 @@ export const defineGetVulnerabilitiesDashboardRoute = (router: CspRouter): void { path: VULNERABILITIES_DASHBOARD_ROUTE_PATH, validate: false, - options: { - tags: ['access:cloud-security-posture-read'], + security: { + authz: { + requiredPrivileges: ['cloud-security-posture-read'], + }, }, }, async (context, request, response) => { diff --git a/x-pack/plugins/data_usage/common/test_utils/test_query_client_options.ts b/x-pack/plugins/data_usage/common/test_utils/test_query_client_options.ts new file mode 100644 index 000000000000..c674e9b342ee --- /dev/null +++ b/x-pack/plugins/data_usage/common/test_utils/test_query_client_options.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. + */ +/* eslint-disable no-console */ +export const dataUsageTestQueryClientOptions = { + defaultOptions: { + queries: { + retry: false, + cacheTime: 0, + }, + }, + logger: { + log: console.log, + warn: console.warn, + error: () => {}, + }, +}; diff --git a/x-pack/plugins/data_usage/kibana.jsonc b/x-pack/plugins/data_usage/kibana.jsonc index ffd883335126..3706875c1ad9 100644 --- a/x-pack/plugins/data_usage/kibana.jsonc +++ b/x-pack/plugins/data_usage/kibana.jsonc @@ -5,6 +5,8 @@ "@elastic/obs-ai-assistant", "@elastic/security-solution" ], + "group": "platform", + "visibility": "private", "plugin": { "id": "dataUsage", "server": true, diff --git a/x-pack/plugins/data_usage/public/app/components/charts.tsx b/x-pack/plugins/data_usage/public/app/components/charts.tsx index 8d04324fb224..56857e7a63ff 100644 --- a/x-pack/plugins/data_usage/public/app/components/charts.tsx +++ b/x-pack/plugins/data_usage/public/app/components/charts.tsx @@ -9,18 +9,21 @@ import { EuiFlexGroup } from '@elastic/eui'; import { MetricTypes } from '../../../common/rest_types'; import { ChartPanel } from './chart_panel'; import { UsageMetricsResponseSchemaBody } from '../../../common/rest_types'; +import { useTestIdGenerator } from '../../hooks/use_test_id_generator'; interface ChartsProps { data: UsageMetricsResponseSchemaBody; + 'data-test-subj'?: string; } -export const Charts: React.FC = ({ data }) => { +export const Charts: React.FC = ({ data, 'data-test-subj': dataTestSubj }) => { + const getTestId = useTestIdGenerator(dataTestSubj); const [popoverOpen, setPopoverOpen] = useState(null); const togglePopover = useCallback((streamName: string | null) => { setPopoverOpen((prev) => (prev === streamName ? null : streamName)); }, []); return ( - + {Object.entries(data.metrics).map(([metricType, series], idx) => ( { + return { + useBreadcrumbs: jest.fn(), + }; +}); + +jest.mock('../../utils/use_kibana', () => { + return { + useKibanaContextForPlugin: () => ({ + services: mockServices, + }), + }; +}); + +jest.mock('../../hooks/use_get_usage_metrics', () => { + const original = jest.requireActual('../../hooks/use_get_usage_metrics'); + return { + ...original, + useGetDataUsageMetrics: jest.fn(original.useGetDataUsageMetrics), + }; +}); + +const mockUseLocation = jest.fn(() => ({ pathname: '/' })); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => mockUseLocation(), + useHistory: jest.fn().mockReturnValue({ + push: jest.fn(), + listen: jest.fn(), + location: { + search: '', + }, + }), +})); + +jest.mock('../../hooks/use_get_data_streams', () => { + const original = jest.requireActual('../../hooks/use_get_data_streams'); + return { + ...original, + useGetDataUsageDataStreams: jest.fn(original.useGetDataUsageDataStreams), + }; +}); + +jest.mock('@kbn/kibana-react-plugin/public', () => { + const original = jest.requireActual('@kbn/kibana-react-plugin/public'); + return { + ...original, + useKibana: () => ({ + services: { + uiSettings: { + get: jest.fn().mockImplementation((key) => { + const get = (k: 'dateFormat' | 'timepicker:quickRanges') => { + const x = { + dateFormat: 'MMM D, YYYY @ HH:mm:ss.SSS', + 'timepicker:quickRanges': [ + { + from: 'now/d', + to: 'now/d', + display: 'Today', + }, + { + from: 'now/w', + to: 'now/w', + display: 'This week', + }, + { + from: 'now-15m', + to: 'now', + display: 'Last 15 minutes', + }, + { + from: 'now-30m', + to: 'now', + display: 'Last 30 minutes', + }, + { + from: 'now-1h', + to: 'now', + display: 'Last 1 hour', + }, + { + from: 'now-24h', + to: 'now', + display: 'Last 24 hours', + }, + { + from: 'now-7d', + to: 'now', + display: 'Last 7 days', + }, + { + from: 'now-30d', + to: 'now', + display: 'Last 30 days', + }, + { + from: 'now-90d', + to: 'now', + display: 'Last 90 days', + }, + { + from: 'now-1y', + to: 'now', + display: 'Last 1 year', + }, + ], + }; + return x[k]; + }; + return get(key); + }), + }, + }, + }), + }; +}); +const mockUseGetDataUsageMetrics = useGetDataUsageMetrics as jest.Mock; +const mockUseGetDataUsageDataStreams = useGetDataUsageDataStreams as jest.Mock; +const mockServices = mockCore.createStart(); + +const getBaseMockedDataStreams = () => ({ + error: undefined, + data: undefined, + isFetching: false, + refetch: jest.fn(), +}); +const getBaseMockedDataUsageMetrics = () => ({ + error: undefined, + data: undefined, + isFetching: false, + refetch: jest.fn(), +}); + +describe('DataUsageMetrics', () => { + let user: UserEvent; + const testId = 'test'; + const testIdFilter = `${testId}-filter`; + + beforeAll(() => { + jest.useFakeTimers(); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + + beforeEach(() => { + jest.clearAllMocks(); + user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime, pointerEventsCheck: 0 }); + mockUseGetDataUsageMetrics.mockReturnValue(getBaseMockedDataUsageMetrics); + mockUseGetDataUsageDataStreams.mockReturnValue(getBaseMockedDataStreams); + }); + + it('renders', () => { + const { getByTestId } = render(); + expect(getByTestId(`${testId}`)).toBeTruthy(); + }); + + it('should show date filter', () => { + const { getByTestId } = render(); + expect(getByTestId(`${testIdFilter}-date-range`)).toBeTruthy(); + expect(getByTestId(`${testIdFilter}-date-range`).textContent).toContain('Last 24 hours'); + expect(getByTestId(`${testIdFilter}-super-refresh-button`)).toBeTruthy(); + }); + + it('should not show data streams filter while fetching API', () => { + mockUseGetDataUsageDataStreams.mockReturnValue({ + ...getBaseMockedDataStreams, + isFetching: true, + }); + const { queryByTestId } = render(); + expect(queryByTestId(`${testIdFilter}-dataStreams-popoverButton`)).not.toBeTruthy(); + }); + + it('should show data streams filter', () => { + const { getByTestId } = render(); + expect(getByTestId(`${testIdFilter}-dataStreams-popoverButton`)).toBeTruthy(); + }); + + it('should show selected data streams on the filter', () => { + mockUseGetDataUsageDataStreams.mockReturnValue({ + error: undefined, + data: [ + { + name: '.ds-1', + storageSizeBytes: 10000, + }, + { + name: '.ds-2', + storageSizeBytes: 20000, + }, + { + name: '.ds-3', + storageSizeBytes: 10300, + }, + { + name: '.ds-4', + storageSizeBytes: 23000, + }, + { + name: '.ds-5', + storageSizeBytes: 23200, + }, + ], + isFetching: false, + }); + const { getByTestId } = render(); + expect(getByTestId(`${testIdFilter}-dataStreams-popoverButton`)).toHaveTextContent( + 'Data streams5' + ); + }); + + it('should allow de-selecting all but one data stream option', async () => { + mockUseGetDataUsageDataStreams.mockReturnValue({ + error: undefined, + data: [ + { + name: '.ds-1', + storageSizeBytes: 10000, + }, + { + name: '.ds-2', + storageSizeBytes: 20000, + }, + { + name: '.ds-3', + storageSizeBytes: 10300, + }, + { + name: '.ds-4', + storageSizeBytes: 23000, + }, + { + name: '.ds-5', + storageSizeBytes: 23200, + }, + ], + isFetching: false, + }); + const { getByTestId, getAllByTestId } = render(); + expect(getByTestId(`${testIdFilter}-dataStreams-popoverButton`)).toHaveTextContent( + 'Data streams5' + ); + await user.click(getByTestId(`${testIdFilter}-dataStreams-popoverButton`)); + const allFilterOptions = getAllByTestId('dataStreams-filter-option'); + for (let i = 0; i < allFilterOptions.length - 1; i++) { + await user.click(allFilterOptions[i]); + } + + expect(getByTestId(`${testIdFilter}-dataStreams-popoverButton`)).toHaveTextContent( + 'Data streams1' + ); + }); + + it('should not call usage metrics API if no data streams', async () => { + mockUseGetDataUsageDataStreams.mockReturnValue({ + ...getBaseMockedDataStreams, + data: [], + }); + render(); + expect(mockUseGetDataUsageMetrics).toHaveBeenCalledWith( + expect.any(Object), + expect.objectContaining({ enabled: false }) + ); + }); + + it('should show charts loading if data usage metrics API is fetching', () => { + mockUseGetDataUsageMetrics.mockReturnValue({ + ...getBaseMockedDataUsageMetrics, + isFetching: true, + }); + const { getByTestId } = render(); + expect(getByTestId(`${testId}-charts-loading`)).toBeTruthy(); + }); + + it('should show charts', () => { + mockUseGetDataUsageMetrics.mockReturnValue({ + ...getBaseMockedDataUsageMetrics, + isFetched: true, + data: { + metrics: { + ingest_rate: [ + { + name: '.ds-1', + data: [{ x: new Date(), y: 1000 }], + }, + { + name: '.ds-10', + data: [{ x: new Date(), y: 1100 }], + }, + ], + storage_retained: [ + { + name: '.ds-2', + data: [{ x: new Date(), y: 2000 }], + }, + { + name: '.ds-20', + data: [{ x: new Date(), y: 2100 }], + }, + ], + }, + }, + }); + const { getByTestId } = render(); + expect(getByTestId(`${testId}-charts`)).toBeTruthy(); + }); + + it('should refetch usage metrics with `Refresh` button click', async () => { + const refetch = jest.fn(); + mockUseGetDataUsageMetrics.mockReturnValue({ + ...getBaseMockedDataUsageMetrics, + data: ['.ds-1', '.ds-2'], + isFetched: true, + }); + mockUseGetDataUsageMetrics.mockReturnValue({ + ...getBaseMockedDataUsageMetrics, + isFetched: true, + refetch, + }); + const { getByTestId } = render(); + const refreshButton = getByTestId(`${testIdFilter}-super-refresh-button`); + // click refresh 5 times + for (let i = 0; i < 5; i++) { + await user.click(refreshButton); + } + + expect(mockUseGetDataUsageMetrics).toHaveBeenLastCalledWith( + expect.any(Object), + expect.objectContaining({ enabled: false }) + ); + expect(refetch).toHaveBeenCalledTimes(5); + }); + + it('should show error toast if usage metrics API fails', async () => { + mockUseGetDataUsageMetrics.mockReturnValue({ + ...getBaseMockedDataUsageMetrics, + isFetched: true, + error: new Error('Uh oh!'), + }); + render(); + await waitFor(() => { + expect(mockServices.notifications.toasts.addDanger).toHaveBeenCalledWith({ + title: 'Error getting usage metrics', + text: 'Uh oh!', + }); + }); + }); + + it('should show error toast if data streams API fails', async () => { + mockUseGetDataUsageDataStreams.mockReturnValue({ + ...getBaseMockedDataStreams, + isFetched: true, + error: new Error('Uh oh!'), + }); + render(); + await waitFor(() => { + expect(mockServices.notifications.toasts.addDanger).toHaveBeenCalledWith({ + title: 'Error getting data streams', + text: 'Uh oh!', + }); + }); + }); +}); 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 929ebf7a0249..59354a174634 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 @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { css } from '@emotion/react'; import { EuiFlexGroup, EuiFlexItem, EuiLoadingElastic } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -14,11 +14,12 @@ import { useBreadcrumbs } from '../../utils/use_breadcrumbs'; import { useKibanaContextForPlugin } from '../../utils/use_kibana'; import { PLUGIN_NAME } from '../../../common'; 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_METRIC_TYPES, UsageMetricsRequestBody } from '../../../common/rest_types'; import { ChartFilters, ChartFiltersProps } from './filters/charts_filters'; -import { useGetDataUsageDataStreams } from '../../hooks/use_get_data_streams'; +import { useTestIdGenerator } from '../../hooks/use_test_id_generator'; const EuiItemCss = css` width: 100%; @@ -28,181 +29,188 @@ const FlexItemWithCss = ({ children }: { children: React.ReactNode }) => ( {children} ); -export const DataUsageMetrics = () => { - const { - services: { chrome, appParams, notifications }, - } = useKibanaContextForPlugin(); - useBreadcrumbs([{ text: PLUGIN_NAME }], appParams, chrome); - - const { - metricTypes: metricTypesFromUrl, - dataStreams: dataStreamsFromUrl, - startDate: startDateFromUrl, - endDate: endDateFromUrl, - setUrlMetricTypesFilter, - setUrlDataStreamsFilter, - setUrlDateRangeFilter, - } = useDataUsageMetricsUrlParams(); - - const { - error: errorFetchingDataStreams, - data: dataStreams, - isFetching: isFetchingDataStreams, - } = useGetDataUsageDataStreams({ - selectedDataStreams: dataStreamsFromUrl, - options: { - enabled: true, - retry: false, - }, - }); - - const [metricsFilters, setMetricsFilters] = useState({ - metricTypes: [...DEFAULT_METRIC_TYPES], - dataStreams: [], - from: DEFAULT_DATE_RANGE_OPTIONS.startDate, - to: DEFAULT_DATE_RANGE_OPTIONS.endDate, - }); - - useEffect(() => { - if (!metricTypesFromUrl) { - setUrlMetricTypesFilter(metricsFilters.metricTypes.join(',')); - } - if (!dataStreamsFromUrl && dataStreams) { - setUrlDataStreamsFilter(dataStreams.map((ds) => ds.name).join(',')); - } - if (!startDateFromUrl || !endDateFromUrl) { - setUrlDateRangeFilter({ startDate: metricsFilters.from, endDate: metricsFilters.to }); - } - }, [ - dataStreams, - dataStreamsFromUrl, - endDateFromUrl, - metricTypesFromUrl, - metricsFilters.dataStreams, - metricsFilters.from, - metricsFilters.metricTypes, - metricsFilters.to, - setUrlDataStreamsFilter, - setUrlDateRangeFilter, - setUrlMetricTypesFilter, - startDateFromUrl, - ]); - - useEffect(() => { - setMetricsFilters((prevState) => ({ - ...prevState, - metricTypes: metricTypesFromUrl?.length ? metricTypesFromUrl : prevState.metricTypes, - dataStreams: dataStreamsFromUrl?.length ? dataStreamsFromUrl : prevState.dataStreams, - })); - }, [metricTypesFromUrl, dataStreamsFromUrl]); - - const { dateRangePickerState, onRefreshChange, onTimeChange } = useDateRangePicker(); - - const { - error: errorFetchingDataUsageMetrics, - data, - isFetching, - isFetched, - refetch: refetchDataUsageMetrics, - } = useGetDataUsageMetrics( - { - ...metricsFilters, - from: dateRangePickerState.startDate, - to: dateRangePickerState.endDate, - }, - { - retry: false, - enabled: !!metricsFilters.dataStreams.length, - } - ); - - const onRefresh = useCallback(() => { - refetchDataUsageMetrics(); - }, [refetchDataUsageMetrics]); - - const onChangeDataStreamsFilter = useCallback( - (selectedDataStreams: string[]) => { - setMetricsFilters((prevState) => ({ ...prevState, dataStreams: selectedDataStreams })); - }, - [setMetricsFilters] - ); - - const onChangeMetricTypesFilter = useCallback( - (selectedMetricTypes: string[]) => { - setMetricsFilters((prevState) => ({ ...prevState, metricTypes: selectedMetricTypes })); - }, - [setMetricsFilters] - ); - - const filterOptions: ChartFiltersProps['filterOptions'] = useMemo(() => { - const dataStreamsOptions = dataStreams?.reduce>((acc, ds) => { - acc[ds.name] = ds.storageSizeBytes; - return acc; - }, {}); - - return { - dataStreams: { - filterName: 'dataStreams', - options: dataStreamsOptions ? Object.keys(dataStreamsOptions) : metricsFilters.dataStreams, - appendOptions: dataStreamsOptions, - selectedOptions: metricsFilters.dataStreams, - onChangeFilterOptions: onChangeDataStreamsFilter, - isFilterLoading: isFetchingDataStreams, - }, - metricTypes: { - filterName: 'metricTypes', - options: metricsFilters.metricTypes, - onChangeFilterOptions: onChangeMetricTypesFilter, +export const DataUsageMetrics = memo( + ({ 'data-test-subj': dataTestSubj = 'data-usage-metrics' }: { 'data-test-subj'?: string }) => { + const getTestId = useTestIdGenerator(dataTestSubj); + + const { + services: { chrome, appParams, notifications }, + } = useKibanaContextForPlugin(); + useBreadcrumbs([{ text: PLUGIN_NAME }], appParams, chrome); + + const { + metricTypes: metricTypesFromUrl, + dataStreams: dataStreamsFromUrl, + startDate: startDateFromUrl, + endDate: endDateFromUrl, + setUrlMetricTypesFilter, + setUrlDataStreamsFilter, + setUrlDateRangeFilter, + } = useDataUsageMetricsUrlParams(); + + const { + error: errorFetchingDataStreams, + data: dataStreams, + isFetching: isFetchingDataStreams, + } = useGetDataUsageDataStreams({ + selectedDataStreams: dataStreamsFromUrl, + options: { + enabled: true, + retry: false, }, - }; - }, [ - dataStreams, - isFetchingDataStreams, - metricsFilters.dataStreams, - metricsFilters.metricTypes, - onChangeDataStreamsFilter, - onChangeMetricTypesFilter, - ]); - - if (errorFetchingDataUsageMetrics) { - notifications.toasts.addDanger({ - title: i18n.translate('xpack.dataUsage.getMetrics.addFailure.toast.title', { - defaultMessage: 'Error getting usage metrics', - }), - text: errorFetchingDataUsageMetrics.message, }); - } - if (errorFetchingDataStreams) { - notifications.toasts.addDanger({ - title: i18n.translate('xpack.dataUsage.getDataStreams.addFailure.toast.title', { - defaultMessage: 'Error getting data streams', - }), - text: errorFetchingDataStreams.message, + + const [metricsFilters, setMetricsFilters] = useState({ + metricTypes: [...DEFAULT_METRIC_TYPES], + dataStreams: [], + from: DEFAULT_DATE_RANGE_OPTIONS.startDate, + to: DEFAULT_DATE_RANGE_OPTIONS.endDate, }); - } - return ( - - - - - - - {isFetched && data?.metrics ? ( - - ) : isFetching ? ( - - ) : null} - - - ); -}; + useEffect(() => { + if (!metricTypesFromUrl) { + setUrlMetricTypesFilter(metricsFilters.metricTypes.join(',')); + } + if (!dataStreamsFromUrl && dataStreams) { + setUrlDataStreamsFilter(dataStreams.map((ds) => ds.name).join(',')); + } + if (!startDateFromUrl || !endDateFromUrl) { + setUrlDateRangeFilter({ startDate: metricsFilters.from, endDate: metricsFilters.to }); + } + }, [ + dataStreams, + dataStreamsFromUrl, + endDateFromUrl, + metricTypesFromUrl, + metricsFilters.dataStreams, + metricsFilters.from, + metricsFilters.metricTypes, + metricsFilters.to, + setUrlDataStreamsFilter, + setUrlDateRangeFilter, + setUrlMetricTypesFilter, + startDateFromUrl, + ]); + + useEffect(() => { + setMetricsFilters((prevState) => ({ + ...prevState, + metricTypes: metricTypesFromUrl?.length ? metricTypesFromUrl : prevState.metricTypes, + dataStreams: dataStreamsFromUrl?.length ? dataStreamsFromUrl : prevState.dataStreams, + })); + }, [metricTypesFromUrl, dataStreamsFromUrl]); + + const { dateRangePickerState, onRefreshChange, onTimeChange } = useDateRangePicker(); + + const { + error: errorFetchingDataUsageMetrics, + data, + isFetching, + isFetched, + refetch: refetchDataUsageMetrics, + } = useGetDataUsageMetrics( + { + ...metricsFilters, + from: dateRangePickerState.startDate, + to: dateRangePickerState.endDate, + }, + { + retry: false, + enabled: !!metricsFilters.dataStreams.length, + } + ); + + const onRefresh = useCallback(() => { + refetchDataUsageMetrics(); + }, [refetchDataUsageMetrics]); + + const onChangeDataStreamsFilter = useCallback( + (selectedDataStreams: string[]) => { + setMetricsFilters((prevState) => ({ ...prevState, dataStreams: selectedDataStreams })); + }, + [setMetricsFilters] + ); + + const onChangeMetricTypesFilter = useCallback( + (selectedMetricTypes: string[]) => { + setMetricsFilters((prevState) => ({ ...prevState, metricTypes: selectedMetricTypes })); + }, + [setMetricsFilters] + ); + + const filterOptions: ChartFiltersProps['filterOptions'] = useMemo(() => { + const dataStreamsOptions = dataStreams?.reduce>((acc, ds) => { + acc[ds.name] = ds.storageSizeBytes; + return acc; + }, {}); + + return { + dataStreams: { + filterName: 'dataStreams', + options: dataStreamsOptions + ? Object.keys(dataStreamsOptions) + : metricsFilters.dataStreams, + appendOptions: dataStreamsOptions, + selectedOptions: metricsFilters.dataStreams, + onChangeFilterOptions: onChangeDataStreamsFilter, + isFilterLoading: isFetchingDataStreams, + }, + metricTypes: { + filterName: 'metricTypes', + options: metricsFilters.metricTypes, + onChangeFilterOptions: onChangeMetricTypesFilter, + }, + }; + }, [ + dataStreams, + isFetchingDataStreams, + metricsFilters.dataStreams, + metricsFilters.metricTypes, + onChangeDataStreamsFilter, + onChangeMetricTypesFilter, + ]); + + if (errorFetchingDataUsageMetrics) { + notifications.toasts.addDanger({ + title: i18n.translate('xpack.dataUsage.getMetrics.addFailure.toast.title', { + defaultMessage: 'Error getting usage metrics', + }), + text: errorFetchingDataUsageMetrics.message, + }); + } + if (errorFetchingDataStreams) { + notifications.toasts.addDanger({ + title: i18n.translate('xpack.dataUsage.getDataStreams.addFailure.toast.title', { + defaultMessage: 'Error getting data streams', + }), + text: errorFetchingDataStreams.message, + }); + } + + return ( + + + + + + + {isFetched && data?.metrics ? ( + + ) : isFetching ? ( + + ) : null} + + + ); + } +); diff --git a/x-pack/plugins/data_usage/public/app/components/filters/charts_filter.tsx b/x-pack/plugins/data_usage/public/app/components/filters/charts_filter.tsx index 83d417565f01..6b4806537e74 100644 --- a/x-pack/plugins/data_usage/public/app/components/filters/charts_filter.tsx +++ b/x-pack/plugins/data_usage/public/app/components/filters/charts_filter.tsx @@ -193,13 +193,10 @@ export const ChartsFilter = memo( > {(list, search) => { return ( -
    +
    {isSearchable && ( {search} diff --git a/x-pack/plugins/data_usage/public/app/components/filters/charts_filter_popover.tsx b/x-pack/plugins/data_usage/public/app/components/filters/charts_filter_popover.tsx index 2ed96f012c49..3c0237c84a0c 100644 --- a/x-pack/plugins/data_usage/public/app/components/filters/charts_filter_popover.tsx +++ b/x-pack/plugins/data_usage/public/app/components/filters/charts_filter_popover.tsx @@ -42,7 +42,7 @@ export const ChartsFilterPopover = memo( const button = useMemo( () => ( ( const filters = useMemo(() => { return ( <> - {showMetricsTypesFilter && } + {showMetricsTypesFilter && ( + + )} {!filterOptions.dataStreams.isFilterLoading && ( - + )} ); - }, [filterOptions, showMetricsTypesFilter]); + }, [dataTestSubj, filterOptions, showMetricsTypesFilter]); const onClickRefreshButton = useCallback(() => onClick(), [onClick]); @@ -68,6 +70,7 @@ export const ChartFilters = memo( onRefresh={onRefresh} onRefreshChange={onRefreshChange} onTimeChange={onTimeChange} + data-test-subj={dataTestSubj} /> 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 4d9b280d763c..044a036eea61 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,6 +15,7 @@ import type { OnRefreshChangeProps, } from '@elastic/eui/src/components/date_picker/types'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; +import { useTestIdGenerator } from '../../../hooks/use_test_id_generator'; export interface DateRangePickerValues { autoRefreshOptions: { @@ -32,10 +33,19 @@ interface UsageMetricsDateRangePickerProps { onRefresh: () => void; onRefreshChange: (evt: OnRefreshChangeProps) => void; onTimeChange: ({ start, end }: DurationRange) => void; + 'data-test-subj'?: string; } export const UsageMetricsDateRangePicker = memo( - ({ dateRangePickerState, isDataLoading, onRefresh, onRefreshChange, onTimeChange }) => { + ({ + dateRangePickerState, + isDataLoading, + onRefresh, + onRefreshChange, + onTimeChange, + 'data-test-subj': dataTestSubj, + }) => { + const getTestId = useTestIdGenerator(dataTestSubj); const kibana = useKibana(); const { uiSettings } = kibana.services; const [commonlyUsedRanges] = useState(() => { @@ -54,6 +64,7 @@ export const UsageMetricsDateRangePicker = memo { + const getMetricTypesAsArray = (): MetricTypes[] => { + return [...METRIC_TYPE_VALUES]; + }; + + it('should not use invalid `metricTypes` values from URL params', () => { + expect(getDataUsageMetricsFiltersFromUrlParams({ metricTypes: 'bar,foo' })).toEqual({}); + }); + + it('should use valid `metricTypes` values from URL params', () => { + expect( + getDataUsageMetricsFiltersFromUrlParams({ + metricTypes: `${getMetricTypesAsArray().join()},foo,bar`, + }) + ).toEqual({ + metricTypes: getMetricTypesAsArray().sort(), + }); + }); + + it('should use given `dataStreams` values from URL params', () => { + expect( + getDataUsageMetricsFiltersFromUrlParams({ + dataStreams: 'ds-3,ds-1,ds-2', + }) + ).toEqual({ + dataStreams: ['ds-3', 'ds-1', 'ds-2'], + }); + }); + + it('should use valid `metricTypes` along with given `dataStreams` and date values from URL params', () => { + expect( + getDataUsageMetricsFiltersFromUrlParams({ + metricTypes: getMetricTypesAsArray().join(), + dataStreams: 'ds-5,ds-1,ds-2', + startDate: '2022-09-12T08:00:00.000Z', + endDate: '2022-09-12T08:30:33.140Z', + }) + ).toEqual({ + metricTypes: getMetricTypesAsArray().sort(), + endDate: '2022-09-12T08:30:33.140Z', + dataStreams: ['ds-5', 'ds-1', 'ds-2'], + startDate: '2022-09-12T08:00:00.000Z', + }); + }); + + it('should use given relative startDate and endDate values URL params', () => { + expect( + getDataUsageMetricsFiltersFromUrlParams({ + startDate: 'now-24h/h', + endDate: 'now', + }) + ).toEqual({ + endDate: 'now', + startDate: 'now-24h/h', + }); + }); + + it('should use given absolute startDate and endDate values URL params', () => { + expect( + getDataUsageMetricsFiltersFromUrlParams({ + startDate: '2022-09-12T08:00:00.000Z', + endDate: '2022-09-12T08:30:33.140Z', + }) + ).toEqual({ + endDate: '2022-09-12T08:30:33.140Z', + startDate: '2022-09-12T08:00:00.000Z', + }); + }); +}); 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 new file mode 100644 index 000000000000..04cee589a523 --- /dev/null +++ b/x-pack/plugins/data_usage/public/hooks/use_get_data_streams.test.tsx @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { ReactNode } from 'react'; +import { QueryClient, QueryClientProvider, useQuery as _useQuery } from '@tanstack/react-query'; +import { renderHook } from '@testing-library/react-hooks'; +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'; +import { dataUsageTestQueryClientOptions } from '../../common/test_utils/test_query_client_options'; + +const useQueryMock = _useQuery as jest.Mock; + +jest.mock('@tanstack/react-query', () => { + const actualReactQueryModule = jest.requireActual('@tanstack/react-query'); + + return { + ...actualReactQueryModule, + useQuery: jest.fn((...args) => actualReactQueryModule.useQuery(...args)), + }; +}); + +const mockServices = mockCore.createStart(); +const createWrapper = () => { + const queryClient = new QueryClient(dataUsageTestQueryClientOptions); + return ({ children }: { children: ReactNode }) => ( + {children} + ); +}; + +jest.mock('../utils/use_kibana', () => { + return { + useKibanaContextForPlugin: () => ({ + services: mockServices, + }), + }; +}); + +const defaultDataStreamsRequestParams = { + options: { enabled: true }, +}; + +describe('useGetDataUsageDataStreams', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should call the correct API', async () => { + await renderHook(() => useGetDataUsageDataStreams(defaultDataStreamsRequestParams), { + wrapper: createWrapper(), + }); + + expect(mockServices.http.get).toHaveBeenCalledWith(DATA_USAGE_DATA_STREAMS_API_ROUTE, { + signal: expect.any(AbortSignal), + version: '1', + }); + }); + + it('should not send selected data stream names provided in the param when calling the API', async () => { + await renderHook( + () => + useGetDataUsageDataStreams({ + ...defaultDataStreamsRequestParams, + selectedDataStreams: ['ds-1'], + }), + { + wrapper: createWrapper(), + } + ); + + expect(mockServices.http.get).toHaveBeenCalledWith(DATA_USAGE_DATA_STREAMS_API_ROUTE, { + signal: expect.any(AbortSignal), + version: '1', + }); + }); + + it('should not call the API if disabled', async () => { + await renderHook( + () => + useGetDataUsageDataStreams({ + ...defaultDataStreamsRequestParams, + options: { enabled: false }, + }), + { + wrapper: createWrapper(), + } + ); + + expect(mockServices.http.get).not.toHaveBeenCalled(); + }); + + it('should allow custom options to be used', async () => { + await renderHook( + () => + useGetDataUsageDataStreams({ + selectedDataStreams: undefined, + options: { + queryKey: ['test-query-key'], + enabled: true, + retry: false, + }, + }), + { + wrapper: createWrapper(), + } + ); + + expect(useQueryMock).toHaveBeenCalledWith( + expect.objectContaining({ + queryKey: ['test-query-key'], + enabled: true, + retry: false, + }) + ); + }); +}); diff --git a/x-pack/plugins/data_usage/public/hooks/use_get_data_streams.ts b/x-pack/plugins/data_usage/public/hooks/use_get_data_streams.ts index 598acca3c1fa..acb41e45f4eb 100644 --- a/x-pack/plugins/data_usage/public/hooks/use_get_data_streams.ts +++ b/x-pack/plugins/data_usage/public/hooks/use_get_data_streams.ts @@ -31,15 +31,16 @@ export const useGetDataUsageDataStreams = ({ selectedDataStreams?: string[]; options?: UseQueryOptions; }): UseQueryResult => { - const http = useKibanaContextForPlugin().services.http; + const { http } = useKibanaContextForPlugin().services; return useQuery({ queryKey: ['get-data-usage-data-streams'], ...options, keepPreviousData: true, - queryFn: async () => { + queryFn: async ({ signal }) => { const dataStreamsResponse = await http .get(DATA_USAGE_DATA_STREAMS_API_ROUTE, { + signal, version: '1', }) .catch((error) => { 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 new file mode 100644 index 000000000000..efc3d2a9f464 --- /dev/null +++ b/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.test.tsx @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { ReactNode } from 'react'; +import { QueryClient, QueryClientProvider, useQuery as _useQuery } from '@tanstack/react-query'; +import { renderHook } from '@testing-library/react-hooks'; +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 } from '../../common/test_utils/test_query_client_options'; + +const useQueryMock = _useQuery as jest.Mock; + +jest.mock('@tanstack/react-query', () => { + const actualReactQueryModule = jest.requireActual('@tanstack/react-query'); + + return { + ...actualReactQueryModule, + useQuery: jest.fn((...args) => actualReactQueryModule.useQuery(...args)), + }; +}); + +const mockServices = mockCore.createStart(); +const createWrapper = () => { + const queryClient = new QueryClient(dataUsageTestQueryClientOptions); + return ({ children }: { children: ReactNode }) => ( + {children} + ); +}; + +jest.mock('../utils/use_kibana', () => { + return { + useKibanaContextForPlugin: () => ({ + services: mockServices, + }), + }; +}); + +const defaultUsageMetricsRequestBody = { + from: 'now-15m', + to: 'now', + metricTypes: ['ingest_rate'], + dataStreams: ['ds-1'], +}; + +describe('useGetDataUsageMetrics', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should call the correct API', async () => { + await renderHook( + () => useGetDataUsageMetrics(defaultUsageMetricsRequestBody, { enabled: true }), + { + wrapper: createWrapper(), + } + ); + + expect(mockServices.http.post).toHaveBeenCalledWith(DATA_USAGE_METRICS_API_ROUTE, { + signal: expect.any(AbortSignal), + version: '1', + body: JSON.stringify(defaultUsageMetricsRequestBody), + }); + }); + + it('should not call the API if disabled', async () => { + await renderHook( + () => useGetDataUsageMetrics(defaultUsageMetricsRequestBody, { enabled: false }), + { + wrapper: createWrapper(), + } + ); + + expect(mockServices.http.post).not.toHaveBeenCalled(); + }); + + it('should allow custom options to be used', async () => { + await renderHook( + () => + useGetDataUsageMetrics(defaultUsageMetricsRequestBody, { + queryKey: ['test-query-key'], + enabled: true, + retry: false, + }), + { + wrapper: createWrapper(), + } + ); + + expect(useQueryMock).toHaveBeenCalledWith( + expect.objectContaining({ + queryKey: ['test-query-key'], + enabled: true, + retry: 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 7e7406d72b9c..6b2ef5316b0f 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 @@ -21,7 +21,7 @@ export const useGetDataUsageMetrics = ( body: UsageMetricsRequestBody, options: UseQueryOptions> = {} ): UseQueryResult> => { - const http = useKibanaContextForPlugin().services.http; + const { http } = useKibanaContextForPlugin().services; return useQuery>({ queryKey: ['get-data-usage-metrics', body], diff --git a/x-pack/plugins/data_usage/public/utils/format_bytes.test.ts b/x-pack/plugins/data_usage/public/utils/format_bytes.test.ts new file mode 100644 index 000000000000..ccc7a4c2f0aa --- /dev/null +++ b/x-pack/plugins/data_usage/public/utils/format_bytes.test.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { formatBytes } from './format_bytes'; + +const exponentN = (number: number, exponent: number) => number ** exponent; + +describe('formatBytes', () => { + it('should format bytes to human readable format with decimal', () => { + expect(formatBytes(84 + 5)).toBe('89.0 B'); + expect(formatBytes(1024 + 256)).toBe('1.3 KB'); + expect(formatBytes(1024 + 582)).toBe('1.6 KB'); + expect(formatBytes(exponentN(1024, 2) + 582 * 1024)).toBe('1.6 MB'); + expect(formatBytes(exponentN(1024, 3) + 582 * exponentN(1024, 2))).toBe('1.6 GB'); + expect(formatBytes(exponentN(1024, 4) + 582 * exponentN(1024, 3))).toBe('1.6 TB'); + expect(formatBytes(exponentN(1024, 5) + 582 * exponentN(1024, 4))).toBe('1.6 PB'); + expect(formatBytes(exponentN(1024, 6) + 582 * exponentN(1024, 5))).toBe('1.6 EB'); + expect(formatBytes(exponentN(1024, 7) + 582 * exponentN(1024, 6))).toBe('1.6 ZB'); + expect(formatBytes(exponentN(1024, 8) + 582 * exponentN(1024, 7))).toBe('1.6 YB'); + }); +}); diff --git a/x-pack/plugins/data_usage/server/mocks/index.ts b/x-pack/plugins/data_usage/server/mocks/index.ts new file mode 100644 index 000000000000..54260f7309fc --- /dev/null +++ b/x-pack/plugins/data_usage/server/mocks/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 { loggingSystemMock } from '@kbn/core/server/mocks'; +import { DeepReadonly } from 'utility-types'; +import { PluginInitializerContext } from '@kbn/core/server'; +import { Observable } from 'rxjs'; +import { DataUsageContext } from '../types'; +import { DataUsageConfigType } from '../config'; + +export interface MockedDataUsageContext extends DataUsageContext { + logFactory: ReturnType['get']>; + config$?: Observable; + configInitialValue: DataUsageConfigType; + serverConfig: DeepReadonly; + kibanaInstanceId: PluginInitializerContext['env']['instanceUuid']; + kibanaVersion: PluginInitializerContext['env']['packageInfo']['version']; + kibanaBranch: PluginInitializerContext['env']['packageInfo']['branch']; +} + +export const createMockedDataUsageContext = ( + context: PluginInitializerContext +): MockedDataUsageContext => { + return { + logFactory: loggingSystemMock.create().get(), + config$: context.config.create(), + configInitialValue: context.config.get(), + serverConfig: context.config.get(), + kibanaInstanceId: context.env.instanceUuid, + kibanaVersion: context.env.packageInfo.version, + kibanaBranch: context.env.packageInfo.branch, + }; +}; diff --git a/x-pack/plugins/data_usage/server/routes/internal/data_streams.test.ts b/x-pack/plugins/data_usage/server/routes/internal/data_streams.test.ts new file mode 100644 index 000000000000..7282dbc969fc --- /dev/null +++ b/x-pack/plugins/data_usage/server/routes/internal/data_streams.test.ts @@ -0,0 +1,124 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { MockedKeys } from '@kbn/utility-types-jest'; +import type { CoreSetup } from '@kbn/core/server'; +import { registerDataStreamsRoute } from './data_streams'; +import { coreMock } from '@kbn/core/server/mocks'; +import { httpServerMock } from '@kbn/core/server/mocks'; +import { DataUsageService } from '../../services'; +import type { + DataUsageRequestHandlerContext, + DataUsageRouter, + DataUsageServerStart, +} from '../../types'; +import { DATA_USAGE_DATA_STREAMS_API_ROUTE } from '../../../common'; +import { createMockedDataUsageContext } from '../../mocks'; +import { getMeteringStats } from '../../utils/get_metering_stats'; +import { CustomHttpRequestError } from '../../utils'; + +jest.mock('../../utils/get_metering_stats'); +const mockGetMeteringStats = getMeteringStats as jest.Mock; + +describe('registerDataStreamsRoute', () => { + let mockCore: MockedKeys>; + let router: DataUsageRouter; + let dataUsageService: DataUsageService; + let context: DataUsageRequestHandlerContext; + + beforeEach(() => { + mockCore = coreMock.createSetup(); + router = mockCore.http.createRouter(); + context = coreMock.createCustomRequestHandlerContext( + coreMock.createRequestHandlerContext() + ) as unknown as DataUsageRequestHandlerContext; + + const mockedDataUsageContext = createMockedDataUsageContext( + coreMock.createPluginInitializerContext() + ); + dataUsageService = new DataUsageService(mockedDataUsageContext); + registerDataStreamsRoute(router, dataUsageService); + }); + + it('should request correct API', () => { + expect(router.versioned.get).toHaveBeenCalledTimes(1); + expect(router.versioned.get).toHaveBeenCalledWith({ + access: 'internal', + path: DATA_USAGE_DATA_STREAMS_API_ROUTE, + }); + }); + + it('should correctly sort response', async () => { + mockGetMeteringStats.mockResolvedValue({ + datastreams: [ + { + name: 'datastream1', + size_in_bytes: 100, + }, + { + name: 'datastream2', + size_in_bytes: 200, + }, + ], + }); + const mockRequest = httpServerMock.createKibanaRequest({ body: {} }); + const mockResponse = httpServerMock.createResponseFactory(); + const mockRouter = mockCore.http.createRouter.mock.results[0].value; + const [[, handler]] = mockRouter.versioned.get.mock.results[0].value.addVersion.mock.calls; + await handler(context, mockRequest, mockResponse); + + expect(mockResponse.ok).toHaveBeenCalledTimes(1); + expect(mockResponse.ok.mock.calls[0][0]).toEqual({ + body: [ + { + name: 'datastream2', + storageSizeBytes: 200, + }, + { + name: 'datastream1', + storageSizeBytes: 100, + }, + ], + }); + }); + + it('should return correct error if metering stats request fails', async () => { + // using custom error for test here to avoid having to import the actual error class + mockGetMeteringStats.mockRejectedValue( + new CustomHttpRequestError('Error getting metring stats!') + ); + const mockRequest = httpServerMock.createKibanaRequest({ body: {} }); + const mockResponse = httpServerMock.createResponseFactory(); + const mockRouter = mockCore.http.createRouter.mock.results[0].value; + const [[, handler]] = mockRouter.versioned.get.mock.results[0].value.addVersion.mock.calls; + await handler(context, mockRequest, mockResponse); + + expect(mockResponse.customError).toHaveBeenCalledTimes(1); + expect(mockResponse.customError).toHaveBeenCalledWith({ + body: new CustomHttpRequestError('Error getting metring stats!'), + statusCode: 500, + }); + }); + + it.each([ + ['no datastreams', {}, []], + ['empty array', { datastreams: [] }, []], + ['an empty element', { datastreams: [{}] }, [{ name: undefined, storageSizeBytes: 0 }]], + ])('should return empty array when no stats data with %s', async (_, stats, res) => { + mockGetMeteringStats.mockResolvedValue(stats); + const mockRequest = httpServerMock.createKibanaRequest({ body: {} }); + const mockResponse = httpServerMock.createResponseFactory(); + const mockRouter = mockCore.http.createRouter.mock.results[0].value; + const [[, handler]] = mockRouter.versioned.get.mock.results[0].value.addVersion.mock.calls; + await handler(context, mockRequest, mockResponse); + + expect(mockResponse.ok).toHaveBeenCalledTimes(1); + expect(mockResponse.ok.mock.calls[0][0]).toEqual({ + body: res, + }); + }); +}); 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 bc8c5e898c35..66c2cc0df351 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 @@ -5,27 +5,11 @@ * 2.0. */ -import { type ElasticsearchClient, RequestHandler } from '@kbn/core/server'; +import { RequestHandler } from '@kbn/core/server'; import { DataUsageRequestHandlerContext } from '../../types'; import { errorHandler } from '../error_handler'; import { DataUsageService } from '../../services'; - -export interface MeteringStats { - name: string; - num_docs: number; - size_in_bytes: number; -} - -interface MeteringStatsResponse { - datastreams: MeteringStats[]; -} - -const getMeteringStats = (client: ElasticsearchClient) => { - return client.transport.request({ - method: 'GET', - path: '/_metering/stats', - }); -}; +import { getMeteringStats } from '../../utils/get_metering_stats'; export const getDataStreamsHandler = ( dataUsageService: DataUsageService @@ -41,12 +25,15 @@ export const getDataStreamsHandler = ( core.elasticsearch.client.asSecondaryAuthUser ); - const body = meteringStats - .sort((a, b) => b.size_in_bytes - a.size_in_bytes) - .map((stat) => ({ - name: stat.name, - storageSizeBytes: stat.size_in_bytes ?? 0, - })); + const body = + meteringStats && !!meteringStats.length + ? meteringStats + .sort((a, b) => b.size_in_bytes - a.size_in_bytes) + .map((stat) => ({ + name: stat.name, + storageSizeBytes: stat.size_in_bytes ?? 0, + })) + : []; return response.ok({ body, 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 new file mode 100644 index 000000000000..e95ffd11807a --- /dev/null +++ b/x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts @@ -0,0 +1,208 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { MockedKeys } from '@kbn/utility-types-jest'; +import type { CoreSetup } from '@kbn/core/server'; +import { registerUsageMetricsRoute } from './usage_metrics'; +import { coreMock } from '@kbn/core/server/mocks'; +import { httpServerMock } from '@kbn/core/server/mocks'; +import { DataUsageService } from '../../services'; +import type { + DataUsageRequestHandlerContext, + DataUsageRouter, + DataUsageServerStart, +} from '../../types'; +import { DATA_USAGE_METRICS_API_ROUTE } from '../../../common'; +import { createMockedDataUsageContext } from '../../mocks'; +import { CustomHttpRequestError } from '../../utils'; +import { AutoOpsError } from '../../services/errors'; + +describe('registerUsageMetricsRoute', () => { + let mockCore: MockedKeys>; + let router: DataUsageRouter; + let dataUsageService: DataUsageService; + let context: DataUsageRequestHandlerContext; + + beforeEach(() => { + mockCore = coreMock.createSetup(); + router = mockCore.http.createRouter(); + context = coreMock.createCustomRequestHandlerContext( + coreMock.createRequestHandlerContext() + ) as unknown as DataUsageRequestHandlerContext; + + const mockedDataUsageContext = createMockedDataUsageContext( + coreMock.createPluginInitializerContext() + ); + dataUsageService = new DataUsageService(mockedDataUsageContext); + }); + + it('should request correct API', () => { + registerUsageMetricsRoute(router, dataUsageService); + + expect(router.versioned.post).toHaveBeenCalledTimes(1); + expect(router.versioned.post).toHaveBeenCalledWith({ + access: 'internal', + path: DATA_USAGE_METRICS_API_ROUTE, + }); + }); + + it('should throw error if no data streams in the request', async () => { + registerUsageMetricsRoute(router, dataUsageService); + + const mockRequest = httpServerMock.createKibanaRequest({ + body: { + from: 'now-15m', + to: 'now', + metricTypes: ['ingest_rate'], + dataStreams: [], + }, + }); + const mockResponse = httpServerMock.createResponseFactory(); + const mockRouter = mockCore.http.createRouter.mock.results[0].value; + const [[, handler]] = mockRouter.versioned.post.mock.results[0].value.addVersion.mock.calls; + await handler(context, mockRequest, mockResponse); + + expect(mockResponse.customError).toHaveBeenCalledTimes(1); + expect(mockResponse.customError).toHaveBeenCalledWith({ + body: new CustomHttpRequestError('[request body.dataStreams]: no data streams selected'), + statusCode: 400, + }); + }); + + it('should correctly transform response', async () => { + (await context.core).elasticsearch.client.asCurrentUser.indices.getDataStream = jest + .fn() + .mockResolvedValue({ + data_streams: [{ name: '.ds-1' }, { name: '.ds-2' }], + }); + + dataUsageService.getMetrics = jest.fn().mockResolvedValue({ + metrics: { + ingest_rate: [ + { + name: '.ds-1', + data: [ + [1726858530000, 13756849], + [1726862130000, 14657904], + ], + }, + { + name: '.ds-2', + data: [ + [1726858530000, 12894623], + [1726862130000, 14436905], + ], + }, + ], + storage_retained: [ + { + name: '.ds-1', + data: [ + [1726858530000, 12576413], + [1726862130000, 13956423], + ], + }, + { + name: '.ds-2', + data: [ + [1726858530000, 12894623], + [1726862130000, 14436905], + ], + }, + ], + }, + }); + + registerUsageMetricsRoute(router, dataUsageService); + + const mockRequest = httpServerMock.createKibanaRequest({ + body: { + from: 'now-15m', + to: 'now', + metricTypes: ['ingest_rate', 'storage_retained'], + dataStreams: ['.ds-1', '.ds-2'], + }, + }); + const mockResponse = httpServerMock.createResponseFactory(); + const mockRouter = mockCore.http.createRouter.mock.results[0].value; + const [[, handler]] = mockRouter.versioned.post.mock.results[0].value.addVersion.mock.calls; + await handler(context, mockRequest, mockResponse); + + expect(mockResponse.ok).toHaveBeenCalledTimes(1); + expect(mockResponse.ok.mock.calls[0][0]).toEqual({ + body: { + metrics: { + ingest_rate: [ + { + name: '.ds-1', + data: [ + { x: 1726858530000, y: 13756849 }, + { x: 1726862130000, y: 14657904 }, + ], + }, + { + name: '.ds-2', + data: [ + { x: 1726858530000, y: 12894623 }, + { x: 1726862130000, y: 14436905 }, + ], + }, + ], + storage_retained: [ + { + name: '.ds-1', + data: [ + { x: 1726858530000, y: 12576413 }, + { x: 1726862130000, y: 13956423 }, + ], + }, + { + name: '.ds-2', + data: [ + { x: 1726858530000, y: 12894623 }, + { x: 1726862130000, y: 14436905 }, + ], + }, + ], + }, + }, + }); + }); + + it('should throw error if error on requesting auto ops service', async () => { + (await context.core).elasticsearch.client.asCurrentUser.indices.getDataStream = jest + .fn() + .mockResolvedValue({ + data_streams: [{ name: '.ds-1' }, { name: '.ds-2' }], + }); + + dataUsageService.getMetrics = jest + .fn() + .mockRejectedValue(new AutoOpsError('Uh oh, something went wrong!')); + + registerUsageMetricsRoute(router, dataUsageService); + + const mockRequest = httpServerMock.createKibanaRequest({ + body: { + from: 'now-15m', + to: 'now', + metricTypes: ['ingest_rate'], + dataStreams: ['.ds-1', '.ds-2'], + }, + }); + const mockResponse = httpServerMock.createResponseFactory(); + const mockRouter = mockCore.http.createRouter.mock.results[0].value; + const [[, handler]] = mockRouter.versioned.post.mock.results[0].value.addVersion.mock.calls; + await handler(context, mockRequest, mockResponse); + + expect(mockResponse.customError).toHaveBeenCalledTimes(1); + expect(mockResponse.customError).toHaveBeenCalledWith({ + body: new AutoOpsError('Uh oh, something went wrong!'), + statusCode: 503, + }); + }); +}); diff --git a/x-pack/plugins/data_usage/server/utils/get_metering_stats.ts b/x-pack/plugins/data_usage/server/utils/get_metering_stats.ts new file mode 100644 index 000000000000..4ba30f5bd360 --- /dev/null +++ b/x-pack/plugins/data_usage/server/utils/get_metering_stats.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { type ElasticsearchClient } from '@kbn/core/server'; + +export interface MeteringStats { + name: string; + num_docs: number; + size_in_bytes: number; +} + +interface MeteringStatsResponse { + datastreams: MeteringStats[]; +} + +export const getMeteringStats = (client: ElasticsearchClient) => { + return client.transport.request({ + method: 'GET', + path: '/_metering/stats', + }); +}; diff --git a/x-pack/plugins/data_usage/tsconfig.json b/x-pack/plugins/data_usage/tsconfig.json index 78c501922f23..66c8a5247858 100644 --- a/x-pack/plugins/data_usage/tsconfig.json +++ b/x-pack/plugins/data_usage/tsconfig.json @@ -31,6 +31,7 @@ "@kbn/repo-info", "@kbn/cloud-plugin", "@kbn/server-http-tools", + "@kbn/utility-types-jest", ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/file_data_visualizer_view/file_data_visualizer_view.js b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/file_data_visualizer_view/file_data_visualizer_view.js index e19b2cbceda3..676830e94a28 100644 --- a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/file_data_visualizer_view/file_data_visualizer_view.js +++ b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/file_data_visualizer_view/file_data_visualizer_view.js @@ -360,9 +360,6 @@ export class FileDataVisualizerView extends Component { fileName={fileName} fileContents={fileContents} data={data} - dataViewsContract={this.props.dataViewsContract} - dataStart={this.props.dataStart} - fileUpload={this.props.fileUpload} getAdditionalLinks={this.props.getAdditionalLinks} resultLinks={this.props.resultLinks} capabilities={this.props.capabilities} diff --git a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_progress/import_progress.tsx b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_progress/import_progress.tsx index 53b92ab1f641..5a6db4f544fd 100644 --- a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_progress/import_progress.tsx +++ b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_progress/import_progress.tsx @@ -31,6 +31,8 @@ export interface Statuses { createDataView: boolean; createPipeline: boolean; permissionCheckStatus: IMPORT_STATUS; + initializeDeployment: boolean; + initializeDeploymentStatus: IMPORT_STATUS; } export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => { @@ -45,6 +47,8 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => { uploadStatus, createDataView, createPipeline, + initializeDeployment, + initializeDeploymentStatus, } = statuses; let statusInfo = null; @@ -58,27 +62,37 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => { ) { completedStep = 0; } + + if ( + readStatus === IMPORT_STATUS.COMPLETE && + initializeDeployment === true && + initializeDeploymentStatus === IMPORT_STATUS.INCOMPLETE + ) { + completedStep = 1; + } + if ( readStatus === IMPORT_STATUS.COMPLETE && + (initializeDeployment === false || initializeDeploymentStatus === IMPORT_STATUS.COMPLETE) && indexCreatedStatus === IMPORT_STATUS.INCOMPLETE && ingestPipelineCreatedStatus === IMPORT_STATUS.INCOMPLETE ) { - completedStep = 1; + completedStep = 2; } if (indexCreatedStatus === IMPORT_STATUS.COMPLETE) { - completedStep = 2; + completedStep = 3; } if ( ingestPipelineCreatedStatus === IMPORT_STATUS.COMPLETE || (createPipeline === false && indexCreatedStatus === IMPORT_STATUS.COMPLETE) ) { - completedStep = 3; + completedStep = 4; } if (uploadStatus === IMPORT_STATUS.COMPLETE) { - completedStep = 4; + completedStep = 5; } if (dataViewCreatedStatus === IMPORT_STATUS.COMPLETE) { - completedStep = 5; + completedStep = 6; } let processFileTitle = i18n.translate( @@ -87,6 +101,12 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => { defaultMessage: 'Process file', } ); + let initializeDeploymentTitle = i18n.translate( + 'xpack.dataVisualizer.file.importProgress.initializeDeploymentTitle', + { + defaultMessage: 'Initialize model deployment', + } + ); let createIndexTitle = i18n.translate( 'xpack.dataVisualizer.file.importProgress.createIndexTitle', { @@ -146,13 +166,43 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => {

    ); } - if (completedStep >= 1) { + if (initializeDeployment) { + if (completedStep >= 1) { + processFileTitle = i18n.translate( + 'xpack.dataVisualizer.file.importProgress.fileProcessedTitle', + { + defaultMessage: 'File processed', + } + ); + initializeDeploymentTitle = i18n.translate( + 'xpack.dataVisualizer.file.importProgress.initializingDeploymentTitle', + { + defaultMessage: 'Initializing model deployment', + } + ); + statusInfo = ( +

    + +

    + ); + } + } + if (completedStep >= 2) { processFileTitle = i18n.translate( 'xpack.dataVisualizer.file.importProgress.fileProcessedTitle', { defaultMessage: 'File processed', } ); + initializeDeploymentTitle = i18n.translate( + 'xpack.dataVisualizer.file.importProgress.deploymentInitializedTitle', + { + defaultMessage: 'Model deployed', + } + ); createIndexTitle = i18n.translate( 'xpack.dataVisualizer.file.importProgress.creatingIndexTitle', { @@ -162,7 +212,7 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => { statusInfo = createPipeline === true ? creatingIndexAndIngestPipelineStatus : creatingIndexStatus; } - if (completedStep >= 2) { + if (completedStep >= 3) { createIndexTitle = i18n.translate( 'xpack.dataVisualizer.file.importProgress.indexCreatedTitle', { @@ -178,7 +228,7 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => { statusInfo = createPipeline === true ? creatingIndexAndIngestPipelineStatus : creatingIndexStatus; } - if (completedStep >= 3) { + if (completedStep >= 4) { createIngestPipelineTitle = i18n.translate( 'xpack.dataVisualizer.file.importProgress.ingestPipelineCreatedTitle', { @@ -193,7 +243,7 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => { ); statusInfo = ; } - if (completedStep >= 4) { + if (completedStep >= 5) { uploadingDataTitle = i18n.translate( 'xpack.dataVisualizer.file.importProgress.dataUploadedTitle', { @@ -219,7 +269,7 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => { statusInfo = null; } } - if (completedStep >= 5) { + if (completedStep >= 6) { createDataViewTitle = i18n.translate( 'xpack.dataVisualizer.file.importProgress.dataViewCreatedTitle', { @@ -239,44 +289,58 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => { : 'selected') as EuiStepStatus, onClick: () => {}, }, - { - title: createIndexTitle, - status: (indexCreatedStatus !== IMPORT_STATUS.INCOMPLETE // Show failure/completed states first - ? indexCreatedStatus + ]; + + if (initializeDeployment === true) { + steps.push({ + title: initializeDeploymentTitle, + status: (initializeDeploymentStatus !== IMPORT_STATUS.INCOMPLETE // Show failure/completed states first + ? initializeDeploymentStatus : completedStep === 1 // Then show selected/incomplete states ? 'selected' : 'incomplete') as EuiStepStatus, onClick: () => {}, - }, - { - title: uploadingDataTitle, - status: (uploadStatus !== IMPORT_STATUS.INCOMPLETE // Show failure/completed states first - ? uploadStatus - : completedStep === 3 // Then show selected/incomplete states - ? 'selected' - : 'incomplete') as EuiStepStatus, - onClick: () => {}, - }, - ]; + }); + } + + steps.push({ + title: createIndexTitle, + status: (indexCreatedStatus !== IMPORT_STATUS.INCOMPLETE // Show failure/completed states first + ? indexCreatedStatus + : completedStep === 2 // Then show selected/incomplete states + ? 'selected' + : 'incomplete') as EuiStepStatus, + onClick: () => {}, + }); if (createPipeline === true) { - steps.splice(2, 0, { + steps.push({ title: createIngestPipelineTitle, status: (ingestPipelineCreatedStatus !== IMPORT_STATUS.INCOMPLETE // Show failure/completed states first ? ingestPipelineCreatedStatus - : completedStep === 2 // Then show selected/incomplete states + : completedStep === 3 // Then show selected/incomplete states ? 'selected' : 'incomplete') as EuiStepStatus, onClick: () => {}, }); } + steps.push({ + title: uploadingDataTitle, + status: (uploadStatus !== IMPORT_STATUS.INCOMPLETE // Show failure/completed states first + ? uploadStatus + : completedStep === 4 // Then show selected/incomplete states + ? 'selected' + : 'incomplete') as EuiStepStatus, + onClick: () => {}, + }); + if (createDataView === true) { steps.push({ title: createDataViewTitle, status: (dataViewCreatedStatus !== IMPORT_STATUS.INCOMPLETE // Show failure/completed states first ? dataViewCreatedStatus - : completedStep === 4 // Then show selected/incomplete states + : completedStep === 5 // Then show selected/incomplete states ? 'selected' : 'incomplete') as EuiStepStatus, onClick: () => {}, @@ -284,21 +348,21 @@ export const ImportProgress: FC<{ statuses: Statuses }> = ({ statuses }) => { } return ( - + <> {statusInfo && ( - + <> {statusInfo} - + )} - + ); }; const UploadFunctionProgress: FC<{ progress: number }> = ({ progress }) => { return ( - + <>

    = ({ progress }) => { />

    {progress < 100 && ( - + <> - + )} -
    + ); }; diff --git a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_view/auto_deploy.ts b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_view/auto_deploy.ts new file mode 100644 index 000000000000..a402d203585d --- /dev/null +++ b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_view/auto_deploy.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { InferenceInferenceEndpointInfo } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { HttpSetup } from '@kbn/core/public'; + +const POLL_INTERVAL = 5; // seconds + +export class AutoDeploy { + private inferError: Error | null = null; + constructor(private readonly http: HttpSetup, private readonly inferenceId: string) {} + + public async deploy() { + this.inferError = null; + if (await this.isDeployed()) { + return; + } + + this.infer().catch((e) => { + // ignore timeout errors + // The deployment may take a long time + // we'll know when it's ready from polling the inference endpoints + // looking for num_allocations + const status = e.response?.status; + if (status === 408 || status === 504 || status === 502) { + return; + } + this.inferError = e; + }); + await this.pollIsDeployed(); + } + + private async infer() { + return this.http.fetch( + `/internal/data_visualizer/inference/${this.inferenceId}`, + { + method: 'POST', + version: '1', + body: JSON.stringify({ input: '' }), + } + ); + } + + private async isDeployed() { + const inferenceEndpoints = await this.http.fetch( + '/internal/data_visualizer/inference_endpoints', + { + method: 'GET', + version: '1', + } + ); + return inferenceEndpoints.some((endpoint) => { + return ( + endpoint.inference_id === this.inferenceId && endpoint.service_settings.num_allocations > 0 + ); + }); + } + + private async pollIsDeployed() { + while (true) { + if (this.inferError !== null) { + throw this.inferError; + } + const isDeployed = await this.isDeployed(); + if (isDeployed) { + // break out of the loop once we have a successful deployment + return; + } + await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL * 1000)); + } + } +} diff --git a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_view/import.ts b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_view/import.ts index 8611e1ccd2ca..a44cb4fb890f 100644 --- a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_view/import.ts +++ b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_view/import.ts @@ -12,13 +12,17 @@ import type { } from '@kbn/file-upload-plugin/common/types'; import type { FileUploadStartApi } from '@kbn/file-upload-plugin/public/api'; import { i18n } from '@kbn/i18n'; +import type { HttpSetup } from '@kbn/core/public'; +import type { MappingTypeMapping } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IMPORT_STATUS } from '../import_progress/import_progress'; +import { AutoDeploy } from './auto_deploy'; interface Props { data: ArrayBuffer; results: FindFileStructureResponse; dataViewsContract: DataViewsServicePublic; fileUpload: FileUploadStartApi; + http: HttpSetup; } interface Config { @@ -33,7 +37,7 @@ interface Config { } export async function importData(props: Props, config: Config, setState: (state: unknown) => void) { - const { data, results, dataViewsContract, fileUpload } = props; + const { data, results, dataViewsContract, fileUpload, http } = props; const { index, dataView, @@ -76,14 +80,6 @@ export async function importData(props: Props, config: Config, setState: (state: return; } - setState({ - importing: true, - imported: false, - reading: true, - initialized: true, - permissionCheckStatus: IMPORT_STATUS.COMPLETE, - }); - let success = true; let settings = {}; @@ -122,7 +118,15 @@ export async function importData(props: Props, config: Config, setState: (state: errors.push(`${parseError} ${error.message}`); } + const inferenceId = getInferenceId(mappings); + setState({ + importing: true, + imported: false, + reading: true, + initialized: true, + permissionCheckStatus: IMPORT_STATUS.COMPLETE, + initializeDeployment: inferenceId !== null, parseJSONStatus: getSuccess(success), }); @@ -147,6 +151,32 @@ export async function importData(props: Props, config: Config, setState: (state: return; } + if (inferenceId) { + // Initialize deployment + const autoDeploy = new AutoDeploy(http, inferenceId); + + try { + await autoDeploy.deploy(); + setState({ + initializeDeploymentStatus: IMPORT_STATUS.COMPLETE, + }); + } catch (error) { + success = false; + const deployError = i18n.translate('xpack.dataVisualizer.file.importView.deployModelError', { + defaultMessage: 'Error deploying trained model:', + }); + errors.push(`${deployError} ${error.message}`); + setState({ + initializeDeploymentStatus: IMPORT_STATUS.FAILED, + errors, + }); + } + } + + if (success === false) { + return; + } + const initializeImportResp = await importer.initializeImport(index, settings, mappings, pipeline); const timeFieldName = importer.getTimeField(); @@ -245,3 +275,12 @@ async function createKibanaDataView( function getSuccess(success: boolean) { return success ? IMPORT_STATUS.COMPLETE : IMPORT_STATUS.FAILED; } + +function getInferenceId(mappings: MappingTypeMapping) { + for (const value of Object.values(mappings.properties ?? {})) { + if (value.type === 'semantic_text') { + return value.inference_id; + } + } + return null; +} diff --git a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_view/import_view.js b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_view/import_view.js index 8481ed76e565..3f3006227006 100644 --- a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_view/import_view.js +++ b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/components/import_view/import_view.js @@ -21,6 +21,7 @@ import { } from '@elastic/eui'; import { debounce } from 'lodash'; +import { context } from '@kbn/kibana-react-plugin/public'; import { ResultsLinks } from '../../../common/components/results_links'; import { FilebeatConfigFlyout } from '../../../common/components/filebeat_config_flyout'; import { ImportProgress, IMPORT_STATUS } from '../import_progress'; @@ -76,14 +77,17 @@ const DEFAULT_STATE = { combinedFields: [], importer: undefined, createPipeline: true, + initializeDeployment: false, + initializeDeploymentStatus: IMPORT_STATUS.INCOMPLETE, }; export class ImportView extends Component { + static contextType = context; + constructor(props) { super(props); this.state = getDefaultState(DEFAULT_STATE, this.props.results, this.props.capabilities); - this.dataViewsContract = props.dataViewsContract; } componentDidMount() { @@ -98,7 +102,12 @@ export class ImportView extends Component { }; clickImport = () => { - const { data, results, dataViewsContract, fileUpload } = this.props; + const { data, results } = this.props; + const { + data: { dataViews: dataViewsContract }, + fileUpload, + http, + } = this.context.services; const { index, dataView, @@ -110,12 +119,13 @@ export class ImportView extends Component { } = this.state; const createPipeline = pipelineString !== ''; + this.setState({ createPipeline, }); importData( - { data, results, dataViewsContract, fileUpload }, + { data, results, dataViewsContract, fileUpload, http }, { index, dataView, @@ -150,7 +160,7 @@ export class ImportView extends Component { return; } - const exists = await this.props.fileUpload.checkIndexExists(index); + const exists = await this.context.services.fileUpload.checkIndexExists(index); const indexNameError = exists ? ( )} diff --git a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/file_data_visualizer.tsx b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/file_data_visualizer.tsx index 01d9d2c37194..6289a73e2a66 100644 --- a/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/file_data_visualizer.tsx +++ b/x-pack/plugins/data_visualizer/public/application/file_data_visualizer/file_data_visualizer.tsx @@ -44,7 +44,6 @@ export const FileDataVisualizer: FC = ({ getAdditionalLinks, resultLinks { - const addFieldStatsAction = createAddFieldStatsTableAction(coreStart, pluginStart); - uiActions.addTriggerAction('ADD_PANEL_TRIGGER', addFieldStatsAction); - }); + const addFieldStatsAction = createAddFieldStatsTableAction(coreStart, pluginStart); + uiActions.addTriggerAction('ADD_PANEL_TRIGGER', addFieldStatsAction); } diff --git a/x-pack/plugins/data_visualizer/server/routes.ts b/x-pack/plugins/data_visualizer/server/routes.ts index 2b2a347034b8..8bede873dc7d 100644 --- a/x-pack/plugins/data_visualizer/server/routes.ts +++ b/x-pack/plugins/data_visualizer/server/routes.ts @@ -96,9 +96,7 @@ export function routes(coreSetup: CoreSetup, logger: Logger) const filteredInferenceEndpoints = endpoints.filter((endpoint) => { return ( - (endpoint.task_type === 'sparse_embedding' || - endpoint.task_type === 'text_embedding') && - endpoint.service_settings.num_allocations >= 0 + endpoint.task_type === 'sparse_embedding' || endpoint.task_type === 'text_embedding' ); }); @@ -108,4 +106,50 @@ export function routes(coreSetup: CoreSetup, logger: Logger) } } ); + + /** + * @apiGroup DataVisualizer + * + * @api {get} /internal/data_visualizer/inference/{inferenceId} Runs inference on a given inference endpoint with the provided input + * @apiName inference + * @apiDescription Runs inference on a given inference endpoint with the provided input. + */ + router.versioned + .post({ + path: '/internal/data_visualizer/inference/{inferenceId}', + access: 'internal', + options: { + tags: ['access:fileUpload:analyzeFile'], + }, + }) + .addVersion( + { + version: '1', + validate: { + request: { + params: schema.object({ + inferenceId: schema.string(), + }), + body: schema.object({ + input: schema.string(), + }), + }, + }, + }, + async (context, request, response) => { + try { + const inferenceId = request.params.inferenceId; + const input = request.body.input; + const esClient = (await context.core).elasticsearch.client; + const body = await esClient.asCurrentUser.inference.inference({ + inference_id: inferenceId, + input, + }); + + return response.ok({ body }); + } catch (e) { + return response.customError(wrapError(e)); + } + } + ); } diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/helpers/get_available_indices.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/helpers/get_available_indices.ts index 8f7fdead5154..85da8b3d539f 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/helpers/get_available_indices.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/helpers/get_available_indices.ts @@ -8,15 +8,15 @@ import type { SearchRequest } from '@elastic/elasticsearch/lib/api/types'; export const getRequestBody = ({ - indexPattern, + indexNameOrPattern, startDate = 'now-7d/d', endDate = 'now/d', }: { - indexPattern: string; + indexNameOrPattern: string; startDate: string; endDate: string; }): SearchRequest => ({ - index: indexPattern, + index: indexNameOrPattern, aggs: { index: { terms: { diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/helpers/get_range_filtered_indices.test.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/helpers/get_range_filtered_indices.test.ts new file mode 100644 index 000000000000..87350abcf8a9 --- /dev/null +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/helpers/get_range_filtered_indices.test.ts @@ -0,0 +1,96 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getRangeFilteredIndices } from './get_range_filtered_indices'; +import { fetchAvailableIndices } from '../lib/fetch_available_indices'; +import type { IScopedClusterClient, Logger } from '@kbn/core/server'; + +jest.mock('../lib/fetch_available_indices'); + +const fetchAvailableIndicesMock = fetchAvailableIndices as jest.Mock; + +describe('getRangeFilteredIndices', () => { + let client: jest.Mocked; + let logger: jest.Mocked; + + beforeEach(() => { + client = { + asCurrentUser: jest.fn(), + } as unknown as jest.Mocked; + + logger = { + warn: jest.fn(), + error: jest.fn(), + } as unknown as jest.Mocked; + + jest.clearAllMocks(); + }); + + describe('when fetching available indices is successful', () => { + describe('and there are available indices', () => { + it('should return the flattened available indices', async () => { + fetchAvailableIndicesMock.mockResolvedValueOnce(['index1', 'index2']); + fetchAvailableIndicesMock.mockResolvedValueOnce(['index3']); + + const result = await getRangeFilteredIndices({ + client, + authorizedIndexNames: ['auth1', 'auth2'], + startDate: '2023-01-01', + endDate: '2023-01-31', + logger, + pattern: 'pattern*', + }); + + expect(fetchAvailableIndices).toHaveBeenCalledTimes(2); + expect(result).toEqual(['index1', 'index2', 'index3']); + expect(logger.warn).not.toHaveBeenCalled(); + }); + }); + + describe('and there are no available indices', () => { + it('should log a warning and return an empty array', async () => { + fetchAvailableIndicesMock.mockResolvedValue([]); + + const result = await getRangeFilteredIndices({ + client, + authorizedIndexNames: ['auth1', 'auth2'], + startDate: '2023-01-01', + endDate: '2023-01-31', + logger, + pattern: 'pattern*', + }); + + expect(fetchAvailableIndices).toHaveBeenCalledTimes(2); + expect(result).toEqual([]); + expect(logger.warn).toHaveBeenCalledWith( + 'No available authorized indices found under pattern: pattern*, in the given date range: 2023-01-01 - 2023-01-31' + ); + }); + }); + }); + + describe('when fetching available indices fails', () => { + it('should log an error and return an empty array', async () => { + fetchAvailableIndicesMock.mockRejectedValue(new Error('Fetch error')); + + const result = await getRangeFilteredIndices({ + client, + authorizedIndexNames: ['auth1'], + startDate: '2023-01-01', + endDate: '2023-01-31', + logger, + pattern: 'pattern*', + }); + + expect(fetchAvailableIndices).toHaveBeenCalledTimes(1); + expect(result).toEqual([]); + expect(logger.error).toHaveBeenCalledWith( + 'Error fetching available indices in the given data range: 2023-01-01 - 2023-01-31' + ); + }); + }); +}); diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/helpers/get_range_filtered_indices.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/helpers/get_range_filtered_indices.ts new file mode 100644 index 000000000000..45a87424169e --- /dev/null +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/helpers/get_range_filtered_indices.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { IScopedClusterClient, Logger } from '@kbn/core/server'; + +import { fetchAvailableIndices } from '../lib/fetch_available_indices'; + +export const getRangeFilteredIndices = async ({ + client, + authorizedIndexNames, + startDate, + endDate, + logger, + pattern, +}: { + client: IScopedClusterClient; + authorizedIndexNames: string[]; + startDate: string; + endDate: string; + logger: Logger; + pattern: string; +}): Promise => { + const decodedStartDate = decodeURIComponent(startDate); + const decodedEndDate = decodeURIComponent(endDate); + try { + const currentUserEsClient = client.asCurrentUser; + + const availableIndicesPromises: Array> = []; + + for (const indexName of authorizedIndexNames) { + availableIndicesPromises.push( + fetchAvailableIndices(currentUserEsClient, { + indexNameOrPattern: indexName, + startDate: decodedStartDate, + endDate: decodedEndDate, + }) + ); + } + + const availableIndices = await Promise.all(availableIndicesPromises); + + const flattenedAvailableIndices = availableIndices.flat(); + + if (flattenedAvailableIndices.length === 0) { + logger.warn( + `No available authorized indices found under pattern: ${pattern}, in the given date range: ${decodedStartDate} - ${decodedEndDate}` + ); + } + + return flattenedAvailableIndices; + } catch (err) { + logger.error( + `Error fetching available indices in the given data range: ${decodedStartDate} - ${decodedEndDate}` + ); + return []; + } +}; diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.test.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.test.ts index fa26fb68289a..9fe8213b4eb9 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.test.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.test.ts @@ -61,7 +61,7 @@ describe('fetchAvailableIndices', () => { const esClientMock = getEsClientMock(); await fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: startDateString, endDate: endDateString, }); @@ -101,7 +101,7 @@ describe('fetchAvailableIndices', () => { const esClientMock = getEsClientMock(); await fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: startDateString, endDate: endDateString, }); @@ -133,7 +133,7 @@ describe('fetchAvailableIndices', () => { ]); const result = await fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: startDateString, endDate: endDateString, }); @@ -164,7 +164,7 @@ describe('fetchAvailableIndices', () => { ]); const result = await fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: startDateString, endDate: endDateString, }); @@ -180,7 +180,7 @@ describe('fetchAvailableIndices', () => { esClientMock.cat.indices.mockResolvedValue([]); const result = await fetchAvailableIndices(esClientMock, { - indexPattern: 'nonexistent-*', + indexNameOrPattern: 'nonexistent-*', startDate: startDateString, endDate: endDateString, }); @@ -209,7 +209,7 @@ describe('fetchAvailableIndices', () => { }); const result = await fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: startDateString, endDate: endDateString, }); @@ -243,7 +243,7 @@ describe('fetchAvailableIndices', () => { }); const result = await fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: startDateString, endDate: endDateString, }); @@ -268,7 +268,7 @@ describe('fetchAvailableIndices', () => { ]); const result = await fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: startDateString, endDate: endDateString, }); @@ -285,7 +285,7 @@ describe('fetchAvailableIndices', () => { await expect( fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: startDateString, endDate: endDateString, }) @@ -307,7 +307,7 @@ describe('fetchAvailableIndices', () => { }); const result = await fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: startDateString, endDate: endDateString, }); @@ -336,7 +336,7 @@ describe('fetchAvailableIndices', () => { }); const result = await fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: startDateString, endDate: endDateString, }); @@ -371,7 +371,7 @@ describe('fetchAvailableIndices', () => { ]); const results = await fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: 'now-7d/d', endDate: 'now/d', }); @@ -390,7 +390,7 @@ describe('fetchAvailableIndices', () => { ]); const results = await fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: 'now-7d/d', endDate: 'now-1d/d', }); @@ -415,7 +415,7 @@ describe('fetchAvailableIndices', () => { await expect( fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: startDateString, endDate: endDateString, }) @@ -429,7 +429,7 @@ describe('fetchAvailableIndices', () => { await expect( fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: 'invalid-date', endDate: endDateString, }) @@ -443,7 +443,7 @@ describe('fetchAvailableIndices', () => { await expect( fetchAvailableIndices(esClientMock, { - indexPattern: 'logs-*', + indexNameOrPattern: 'logs-*', startDate: startDateString, endDate: 'invalid-date', }) diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.ts index 32311f28d636..36009f315010 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/lib/fetch_available_indices.ts @@ -32,15 +32,15 @@ const getParsedDateMs = (dateStr: string, roundUp = false) => { export const fetchAvailableIndices = async ( esClient: ElasticsearchClient, - params: { indexPattern: string; startDate: string; endDate: string } + params: { indexNameOrPattern: string; startDate: string; endDate: string } ): Promise => { - const { indexPattern, startDate, endDate } = params; + const { indexNameOrPattern, startDate, endDate } = params; const startDateMs = getParsedDateMs(startDate); const endDateMs = getParsedDateMs(endDate, true); const indicesCats = (await esClient.cat.indices({ - index: indexPattern, + index: indexNameOrPattern, format: 'json', h: 'index,creation.date', })) as FetchAvailableCatIndicesResponseRequired; diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_stats.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_stats.ts index d1bb25d34fc2..fd1ec1694719 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_stats.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/get_index_stats.ts @@ -85,7 +85,7 @@ export const getIndexStatsRoute = (router: IRouter, logger: Logger) => { const meteringStatsIndices = parseMeteringStats(meteringStats.indices); const availableIndices = await fetchAvailableIndices(esClient, { - indexPattern: decodedIndexName, + indexNameOrPattern: decodedIndexName, startDate: decodedStartDate, endDate: decodedEndDate, }); diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results_latest.test.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results_latest.test.ts index bfb38864916f..94c892e401b5 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results_latest.test.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results_latest.test.ts @@ -16,6 +16,24 @@ import { resultDocument } from './results.mock'; import type { SearchResponse } from '@elastic/elasticsearch/lib/api/types'; import type { ResultDocument } from '../../schemas/result'; import type { CheckIndicesPrivilegesParam } from './privileges'; +import { getRangeFilteredIndices } from '../../helpers/get_range_filtered_indices'; + +const mockCheckIndicesPrivileges = jest.fn(({ indices }: CheckIndicesPrivilegesParam) => + Promise.resolve(Object.fromEntries(indices.map((index) => [index, true]))) +); +jest.mock('./privileges', () => ({ + checkIndicesPrivileges: (params: CheckIndicesPrivilegesParam) => + mockCheckIndicesPrivileges(params), +})); + +jest.mock('../../helpers/get_range_filtered_indices', () => ({ + getRangeFilteredIndices: jest.fn(), +})); + +const mockGetRangeFilteredIndices = getRangeFilteredIndices as jest.Mock; + +const startDate = 'now-7d'; +const endDate = 'now'; const searchResponse = { aggregations: { @@ -33,14 +51,6 @@ const searchResponse = { Record >; -const mockCheckIndicesPrivileges = jest.fn(({ indices }: CheckIndicesPrivilegesParam) => - Promise.resolve(Object.fromEntries(indices.map((index) => [index, true]))) -); -jest.mock('./privileges', () => ({ - checkIndicesPrivileges: (params: CheckIndicesPrivilegesParam) => - mockCheckIndicesPrivileges(params), -})); - describe('getIndexResultsLatestRoute route', () => { describe('querying', () => { let server: ReturnType; @@ -68,7 +78,7 @@ describe('getIndexResultsLatestRoute route', () => { getIndexResultsLatestRoute(server.router, logger); }); - it('gets result', async () => { + it('gets result without startDate and endDate', async () => { const mockSearch = context.core.elasticsearch.client.asInternalUser.search; mockSearch.mockResolvedValueOnce(searchResponse); @@ -80,6 +90,159 @@ describe('getIndexResultsLatestRoute route', () => { expect(response.status).toEqual(200); expect(response.body).toEqual([resultDocument]); + + expect(mockGetRangeFilteredIndices).not.toHaveBeenCalled(); + }); + + it('gets result with startDate and endDate', async () => { + const reqWithDate = requestMock.create({ + method: 'get', + path: GET_INDEX_RESULTS_LATEST, + params: { pattern: 'logs-*' }, + query: { startDate, endDate }, + }); + + const filteredIndices = ['filtered-index-1', 'filtered-index-2']; + mockGetRangeFilteredIndices.mockResolvedValueOnce(filteredIndices); + const mockSearch = context.core.elasticsearch.client.asInternalUser.search; + mockSearch.mockResolvedValueOnce(searchResponse); + + const response = await server.inject(reqWithDate, requestContextMock.convertContext(context)); + + expect(mockGetRangeFilteredIndices).toHaveBeenCalledWith({ + client: context.core.elasticsearch.client, + authorizedIndexNames: [resultDocument.indexName], + startDate, + endDate, + logger, + pattern: 'logs-*', + }); + + expect(mockSearch).toHaveBeenCalledWith({ + index: expect.any(String), + ...getQuery(filteredIndices), + }); + + expect(response.status).toEqual(200); + expect(response.body).toEqual([resultDocument]); + }); + + it('handles getRangeFilteredIndices error', async () => { + const errorMessage = 'Range Filter Error'; + + const reqWithDate = requestMock.create({ + method: 'get', + path: GET_INDEX_RESULTS_LATEST, + params: { pattern: 'logs-*' }, + query: { startDate, endDate }, + }); + + mockGetRangeFilteredIndices.mockRejectedValueOnce(new Error(errorMessage)); + + const response = await server.inject(reqWithDate, requestContextMock.convertContext(context)); + + expect(mockGetRangeFilteredIndices).toHaveBeenCalledWith({ + client: context.core.elasticsearch.client, + authorizedIndexNames: [resultDocument.indexName], + startDate, + endDate, + logger, + pattern: 'logs-*', + }); + + expect(response.status).toEqual(500); + expect(response.body).toEqual({ message: errorMessage, status_code: 500 }); + expect(logger.error).toHaveBeenCalledWith(errorMessage); + }); + + it('gets result with startDate and endDate and multiple filtered indices', async () => { + const filteredIndices = ['filtered-index-1', 'filtered-index-2', 'filtered-index-3']; + const filteredIndicesSearchResponse = { + aggregations: { + latest: { + buckets: filteredIndices.map((indexName) => ({ + key: indexName, + latest_doc: { hits: { hits: [{ _source: { indexName } }] } }, + })), + }, + }, + } as unknown as SearchResponse< + ResultDocument, + Record + >; + + const reqWithDate = requestMock.create({ + method: 'get', + path: GET_INDEX_RESULTS_LATEST, + params: { pattern: 'logs-*' }, + query: { startDate, endDate }, + }); + + mockGetRangeFilteredIndices.mockResolvedValueOnce(filteredIndices); + context.core.elasticsearch.client.asInternalUser.search.mockResolvedValueOnce( + filteredIndicesSearchResponse + ); + + const response = await server.inject(reqWithDate, requestContextMock.convertContext(context)); + + expect(mockGetRangeFilteredIndices).toHaveBeenCalledWith({ + client: context.core.elasticsearch.client, + authorizedIndexNames: [resultDocument.indexName], + startDate, + endDate, + logger, + pattern: 'logs-*', + }); + + expect(context.core.elasticsearch.client.asInternalUser.search).toHaveBeenCalledWith({ + index: expect.any(String), + ...getQuery(filteredIndices), + }); + + const expectedResults = filteredIndices.map((indexName) => ({ + indexName, + })) as ResultDocument[]; + expect(response.status).toEqual(200); + expect(response.body).toEqual(expectedResults); + }); + + it('handles partial authorization when using startDate and endDate', async () => { + const authorizationResult = { + 'filtered-index-1': true, + 'filtered-index-2': false, + }; + + mockGetRangeFilteredIndices.mockResolvedValueOnce(['filtered-index-1']); + mockCheckIndicesPrivileges.mockResolvedValueOnce(authorizationResult); + + const mockSearch = context.core.elasticsearch.client.asInternalUser.search; + mockSearch.mockResolvedValueOnce(searchResponse); + + const reqWithDate = requestMock.create({ + method: 'get', + path: GET_INDEX_RESULTS_LATEST, + params: { pattern: 'logs-*' }, + query: { startDate, endDate }, + }); + + const response = await server.inject(reqWithDate, requestContextMock.convertContext(context)); + + expect(mockGetRangeFilteredIndices).toHaveBeenCalledWith({ + client: context.core.elasticsearch.client, + authorizedIndexNames: ['filtered-index-1'], + startDate, + endDate, + logger, + pattern: 'logs-*', + }); + + expect(context.core.elasticsearch.client.asInternalUser.search).toHaveBeenCalledWith({ + index: expect.any(String), + ...getQuery(['filtered-index-1']), + }); + + expect(response.status).toEqual(200); + expect(response.body).toEqual([resultDocument]); }); it('handles results data stream error', async () => { diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results_latest.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results_latest.ts index 3a294409af86..f7d1d5eed74c 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results_latest.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/routes/results/get_index_results_latest.ts @@ -4,18 +4,18 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import type { IRouter, Logger } from '@kbn/core/server'; import { INTERNAL_API_VERSION, GET_INDEX_RESULTS_LATEST } from '../../../common/constants'; import { buildResponse } from '../../lib/build_response'; import { buildRouteValidation } from '../../schemas/common'; -import { GetIndexResultsLatestParams } from '../../schemas/result'; +import { GetIndexResultsLatestParams, GetIndexResultsLatestQuery } from '../../schemas/result'; import type { ResultDocument } from '../../schemas/result'; import { API_DEFAULT_ERROR_MESSAGE } from '../../translations'; import type { DataQualityDashboardRequestHandlerContext } from '../../types'; import { API_RESULTS_INDEX_NOT_AVAILABLE } from './translations'; import { getAuthorizedIndexNames } from '../../helpers/get_authorized_index_names'; +import { getRangeFilteredIndices } from '../../helpers/get_range_filtered_indices'; export const getQuery = (indexName: string[]) => ({ size: 0, @@ -53,6 +53,7 @@ export const getIndexResultsLatestRoute = ( validate: { request: { params: buildRouteValidation(GetIndexResultsLatestParams), + query: buildRouteValidation(GetIndexResultsLatestQuery), }, }, }, @@ -81,8 +82,27 @@ export const getIndexResultsLatestRoute = ( return response.ok({ body: [] }); } + const { startDate, endDate } = request.query; + + let resultingIndices: string[] = []; + + if (startDate && endDate) { + resultingIndices = resultingIndices.concat( + await getRangeFilteredIndices({ + client, + authorizedIndexNames, + startDate, + endDate, + logger, + pattern, + }) + ); + } else { + resultingIndices = authorizedIndexNames; + } + // Get the latest result for each indexName - const query = { index, ...getQuery(authorizedIndexNames) }; + const query = { index, ...getQuery(resultingIndices) }; const { aggregations } = await client.asInternalUser.search< ResultDocument, Record diff --git a/x-pack/plugins/ecs_data_quality_dashboard/server/schemas/result.ts b/x-pack/plugins/ecs_data_quality_dashboard/server/schemas/result.ts index 8ccb3fbc3f98..fb264fe10da8 100644 --- a/x-pack/plugins/ecs_data_quality_dashboard/server/schemas/result.ts +++ b/x-pack/plugins/ecs_data_quality_dashboard/server/schemas/result.ts @@ -69,6 +69,11 @@ export const PostIndexResultBody = ResultDocument; export const GetIndexResultsLatestParams = t.type({ pattern: t.string }); export type GetIndexResultsLatestParams = t.TypeOf; +export const GetIndexResultsLatestQuery = t.partial({ + startDate: t.string, + endDate: t.string, +}); + export const GetIndexResultsParams = t.type({ pattern: t.string, }); diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts index 09bb5b291ef9..77a1e37df965 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry.ts @@ -6,7 +6,12 @@ */ import { v4 as uuidv4 } from 'uuid'; -import { AuthenticatedUser, ElasticsearchClient, Logger } from '@kbn/core/server'; +import { + AnalyticsServiceSetup, + AuthenticatedUser, + ElasticsearchClient, + Logger, +} from '@kbn/core/server'; import { DocumentEntryCreateFields, @@ -15,6 +20,10 @@ import { KnowledgeBaseEntryUpdateProps, Metadata, } from '@kbn/elastic-assistant-common'; +import { + CREATE_KNOWLEDGE_BASE_ENTRY_ERROR_EVENT, + CREATE_KNOWLEDGE_BASE_ENTRY_SUCCESS_EVENT, +} from '../../lib/telemetry/event_based_telemetry'; import { getKnowledgeBaseEntry } from './get_knowledge_base_entry'; import { CreateKnowledgeBaseEntrySchema, UpdateKnowledgeBaseEntrySchema } from './types'; @@ -27,6 +36,7 @@ export interface CreateKnowledgeBaseEntryParams { knowledgeBaseEntry: KnowledgeBaseEntryCreateProps | LegacyKnowledgeBaseEntryCreateProps; global?: boolean; isV2?: boolean; + telemetry: AnalyticsServiceSetup; } export const createKnowledgeBaseEntry = async ({ @@ -38,6 +48,7 @@ export const createKnowledgeBaseEntry = async ({ logger, global = false, isV2 = false, + telemetry, }: CreateKnowledgeBaseEntryParams): Promise => { const createdAt = new Date().toISOString(); const body = isV2 @@ -55,6 +66,12 @@ export const createKnowledgeBaseEntry = async ({ entry: knowledgeBaseEntry as unknown as TransformToLegacyCreateSchemaProps['entry'], global, }); + const telemetryPayload = { + entryType: body.type, + required: body.required ?? false, + sharing: body.users.length ? 'private' : 'global', + ...(body.type === 'document' ? { source: body.source } : {}), + }; try { const response = await esClient.create({ body, @@ -63,17 +80,24 @@ export const createKnowledgeBaseEntry = async ({ refresh: 'wait_for', }); - return await getKnowledgeBaseEntry({ + const newKnowledgeBaseEntry = await getKnowledgeBaseEntry({ esClient, knowledgeBaseIndex, id: response._id, logger, user, }); + + telemetry.reportEvent(CREATE_KNOWLEDGE_BASE_ENTRY_SUCCESS_EVENT.eventType, telemetryPayload); + return newKnowledgeBaseEntry; } catch (err) { logger.error( `Error creating Knowledge Base Entry: ${err} with kbResource: ${knowledgeBaseEntry.name}` ); + telemetry.reportEvent(CREATE_KNOWLEDGE_BASE_ENTRY_ERROR_EVENT.eventType, { + ...telemetryPayload, + errorMessage: err.message ?? 'Unknown error', + }); throw err; } }; diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts index 333fbb796ddd..50e124321fe6 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts @@ -25,7 +25,7 @@ import { import pRetry from 'p-retry'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { StructuredTool } from '@langchain/core/tools'; -import { ElasticsearchClient } from '@kbn/core/server'; +import { AnalyticsServiceSetup, ElasticsearchClient } from '@kbn/core/server'; import { IndexPatternsFetcher } from '@kbn/data-views-plugin/server'; import { map } from 'lodash'; import { AIAssistantDataClient, AIAssistantDataClientParams } from '..'; @@ -459,6 +459,8 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { filter: docsCreated.map((c) => `_id:${c}`).join(' OR '), }) : undefined; + // Intentionally no telemetry here - this path only used to install security docs + // Plans to make this function private in a different PR so no user entry ever is created in this path this.options.logger.debug(`created: ${created?.data.hits.hits.length ?? '0'}`); this.options.logger.debug(() => `errors: ${JSON.stringify(errors, null, 2)}`); @@ -686,10 +688,12 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { */ public createKnowledgeBaseEntry = async ({ knowledgeBaseEntry, + telemetry, global = false, }: { knowledgeBaseEntry: KnowledgeBaseEntryCreateProps | LegacyKnowledgeBaseEntryCreateProps; global?: boolean; + telemetry: AnalyticsServiceSetup; }): Promise => { const authenticatedUser = this.options.currentUser; @@ -716,6 +720,7 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { user: authenticatedUser, knowledgeBaseEntry, global, + telemetry, isV2: this.options.v2KnowledgeBaseEnabled, }); }; diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts index 3e573aff2f4c..da560dfae72d 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/executors/types.ts @@ -15,6 +15,8 @@ import { ExecuteConnectorRequestBody, Message, Replacements } from '@kbn/elastic import { StreamResponseWithHeaders } from '@kbn/ml-response-stream/server'; import { PublicMethodsOf } from '@kbn/utility-types'; import type { InferenceServerStart } from '@kbn/inference-plugin/server'; +import { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; +import { TelemetryParams } from '@kbn/langchain/server/tracers/telemetry/telemetry_tracer'; import { ResponseBody } from '../types'; import type { AssistantTool } from '../../../types'; import { AIAssistantKnowledgeBaseDataClient } from '../../../ai_assistant_data_clients/knowledge_base'; @@ -55,6 +57,8 @@ export interface AgentExecutorParams { response?: KibanaResponseFactory; size?: number; systemPrompt?: string; + telemetry: AnalyticsServiceSetup; + telemetryParams?: TelemetryParams; traceOptions?: TraceOptions; responseLanguage?: string; } diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts index d1b3514b15b7..0126692b5b6a 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/helpers.ts @@ -7,6 +7,7 @@ import agent, { Span } from 'elastic-apm-node'; import type { Logger } from '@kbn/logging'; +import { TelemetryTracer } from '@kbn/langchain/server/tracers/telemetry'; import { streamFactory, StreamResponseWithHeaders } from '@kbn/ml-response-stream/server'; import { transformError } from '@kbn/securitysolution-es-utils'; import type { KibanaRequest } from '@kbn/core-http-server'; @@ -26,6 +27,7 @@ interface StreamGraphParams { logger: Logger; onLlmResponse?: OnLlmResponse; request: KibanaRequest; + telemetryTracer?: TelemetryTracer; traceOptions?: TraceOptions; } @@ -38,6 +40,7 @@ interface StreamGraphParams { * @param logger * @param onLlmResponse * @param request + * @param telemetryTracer * @param traceOptions */ export const streamGraph = async ({ @@ -47,6 +50,7 @@ export const streamGraph = async ({ logger, onLlmResponse, request, + telemetryTracer, traceOptions, }: StreamGraphParams): Promise => { let streamingSpan: Span | undefined; @@ -84,7 +88,11 @@ export const streamGraph = async ({ const stream = await assistantGraph.streamEvents( inputs, { - callbacks: [apmTracer, ...(traceOptions?.tracers ?? [])], + callbacks: [ + apmTracer, + ...(traceOptions?.tracers ?? []), + ...(telemetryTracer ? [telemetryTracer] : []), + ], runName: DEFAULT_ASSISTANT_GRAPH_ID, tags: traceOptions?.tags ?? [], version: 'v2', @@ -120,7 +128,11 @@ export const streamGraph = async ({ let finalMessage = ''; let conversationId: string | undefined; const stream = assistantGraph.streamEvents(inputs, { - callbacks: [apmTracer, ...(traceOptions?.tracers ?? [])], + callbacks: [ + apmTracer, + ...(traceOptions?.tracers ?? []), + ...(telemetryTracer ? [telemetryTracer] : []), + ], runName: DEFAULT_ASSISTANT_GRAPH_ID, streamMode: 'values', tags: traceOptions?.tags ?? [], @@ -187,6 +199,7 @@ interface InvokeGraphParams { assistantGraph: DefaultAssistantGraph; inputs: GraphInputs; onLlmResponse?: OnLlmResponse; + telemetryTracer?: TelemetryTracer; traceOptions?: TraceOptions; } interface InvokeGraphResponse { @@ -202,6 +215,7 @@ interface InvokeGraphResponse { * @param assistantGraph * @param inputs * @param onLlmResponse + * @param telemetryTracer * @param traceOptions */ export const invokeGraph = async ({ @@ -209,6 +223,7 @@ export const invokeGraph = async ({ assistantGraph, inputs, onLlmResponse, + telemetryTracer, traceOptions, }: InvokeGraphParams): Promise => { return withAssistantSpan(DEFAULT_ASSISTANT_GRAPH_ID, async (span) => { @@ -222,7 +237,11 @@ export const invokeGraph = async ({ span.addLabels({ evaluationId: traceOptions?.evaluationId }); } const r = await assistantGraph.invoke(inputs, { - callbacks: [apmTracer, ...(traceOptions?.tracers ?? [])], + callbacks: [ + apmTracer, + ...(traceOptions?.tracers ?? []), + ...(telemetryTracer ? [telemetryTracer] : []), + ], runName: DEFAULT_ASSISTANT_GRAPH_ID, tags: traceOptions?.tags ?? [], }); diff --git a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/index.ts b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/index.ts index 4f043c681f8d..f55006e452cd 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/index.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/index.ts @@ -13,6 +13,7 @@ import { createToolCallingAgent, } from 'langchain/agents'; import { APMTracer } from '@kbn/langchain/server/tracers/apm'; +import { TelemetryTracer } from '@kbn/langchain/server/tracers/telemetry'; import { getLlmClass } from '../../../../routes/utils'; import { EsAnonymizationFieldsSchema } from '../../../../ai_assistant_data_clients/anonymization_fields/types'; import { AssistantToolParams } from '../../../../types'; @@ -44,6 +45,8 @@ export const callAssistantGraph: AgentExecutor = async ({ request, size, systemPrompt, + telemetry, + telemetryParams, traceOptions, responseLanguage = 'English', }) => { @@ -107,6 +110,7 @@ export const callAssistantGraph: AgentExecutor = async ({ replacements, request, size, + telemetry, }; const tools: StructuredTool[] = assistantTools.flatMap( @@ -150,7 +154,17 @@ export const callAssistantGraph: AgentExecutor = async ({ }); const apmTracer = new APMTracer({ projectName: traceOptions?.projectName ?? 'default' }, logger); - + const telemetryTracer = telemetryParams + ? new TelemetryTracer( + { + elasticTools: assistantTools.map(({ name }) => name), + totalTools: tools.length, + telemetry, + telemetryParams, + }, + logger + ) + : undefined; const assistantGraph = getDefaultAssistantGraph({ agentRunnable, dataClients, @@ -177,6 +191,7 @@ export const callAssistantGraph: AgentExecutor = async ({ logger, onLlmResponse, request, + telemetryTracer, traceOptions, }); } @@ -186,6 +201,7 @@ export const callAssistantGraph: AgentExecutor = async ({ assistantGraph, inputs, onLlmResponse, + telemetryTracer, traceOptions, }); diff --git a/x-pack/plugins/elastic_assistant/server/lib/telemetry/event_based_telemetry.ts b/x-pack/plugins/elastic_assistant/server/lib/telemetry/event_based_telemetry.ts index 5ff5ff894dff..1087703ba13a 100644 --- a/x-pack/plugins/elastic_assistant/server/lib/telemetry/event_based_telemetry.ts +++ b/x-pack/plugins/elastic_assistant/server/lib/telemetry/event_based_telemetry.ts @@ -76,7 +76,16 @@ export const INVOKE_ASSISTANT_SUCCESS_EVENT: EventTypeOpts<{ assistantStreamingEnabled: boolean; actionTypeId: string; isEnabledKnowledgeBase: boolean; + durationMs: number; + ['toolsInvoked.AlertCountsTool']?: number; + ['toolsInvoked.NaturalLanguageESQLTool']?: number; + ['toolsInvoked.KnowledgeBaseRetrievalTool']?: number; + ['toolsInvoked.KnowledgeBaseWriteTool']?: number; + ['toolsInvoked.OpenAndAcknowledgedAlertsTool']?: number; + ['toolsInvoked.SecurityLabsKnowledgeBaseTool']?: number; + ['toolsInvoked.CustomTool']?: number; model?: string; + isOssModel?: boolean; }> = { eventType: 'invoke_assistant_success', schema: { @@ -105,6 +114,68 @@ export const INVOKE_ASSISTANT_SUCCESS_EVENT: EventTypeOpts<{ description: 'Is knowledge base enabled', }, }, + isOssModel: { + type: 'boolean', + _meta: { + description: 'Is OSS model used on the request', + optional: true, + }, + }, + durationMs: { + type: 'integer', + _meta: { + description: 'The duration of the request.', + }, + }, + 'toolsInvoked.AlertCountsTool': { + type: 'long', + _meta: { + description: 'Number of times tool was invoked.', + optional: true, + }, + }, + 'toolsInvoked.NaturalLanguageESQLTool': { + type: 'long', + _meta: { + description: 'Number of times tool was invoked.', + optional: true, + }, + }, + 'toolsInvoked.KnowledgeBaseRetrievalTool': { + type: 'long', + _meta: { + description: 'Number of times tool was invoked.', + optional: true, + }, + }, + 'toolsInvoked.KnowledgeBaseWriteTool': { + type: 'long', + _meta: { + description: 'Number of times tool was invoked.', + optional: true, + }, + }, + 'toolsInvoked.OpenAndAcknowledgedAlertsTool': { + type: 'long', + _meta: { + description: 'Number of times tool was invoked.', + optional: true, + }, + }, + 'toolsInvoked.SecurityLabsKnowledgeBaseTool': { + type: 'long', + _meta: { + description: 'Number of times tool was invoked.', + optional: true, + }, + }, + 'toolsInvoked.CustomTool': { + type: 'long', + _meta: { + description: 'Number of times tool was invoked.', + optional: true, + }, + }, }, }; @@ -261,9 +332,90 @@ export const ATTACK_DISCOVERY_ERROR_EVENT: EventTypeOpts<{ }, }; +export const CREATE_KNOWLEDGE_BASE_ENTRY_SUCCESS_EVENT: EventTypeOpts<{ + entryType: 'index' | 'document'; + required: boolean; + sharing: 'private' | 'global'; + source?: string; +}> = { + eventType: 'create_knowledge_base_entry_success', + schema: { + entryType: { + type: 'keyword', + _meta: { + description: 'Index entry or document entry', + }, + }, + sharing: { + type: 'keyword', + _meta: { + description: 'Sharing setting: private or global', + }, + }, + required: { + type: 'boolean', + _meta: { + description: 'Whether this resource should always be included', + }, + }, + source: { + type: 'keyword', + _meta: { + description: 'Where the knowledge base document entry was created', + optional: true, + }, + }, + }, +}; + +export const CREATE_KNOWLEDGE_BASE_ENTRY_ERROR_EVENT: EventTypeOpts<{ + entryType: 'index' | 'document'; + required: boolean; + sharing: 'private' | 'global'; + source?: string; + errorMessage: string; +}> = { + eventType: 'create_knowledge_base_entry_error', + schema: { + entryType: { + type: 'keyword', + _meta: { + description: 'Index entry or document entry', + }, + }, + sharing: { + type: 'keyword', + _meta: { + description: 'Sharing setting: private or global', + }, + }, + required: { + type: 'boolean', + _meta: { + description: 'Whether this resource should always be included', + }, + }, + source: { + type: 'keyword', + _meta: { + description: 'Where the knowledge base document entry was created', + optional: true, + }, + }, + errorMessage: { + type: 'keyword', + _meta: { + description: 'Error message', + }, + }, + }, +}; + export const events: Array> = [ KNOWLEDGE_BASE_EXECUTION_SUCCESS_EVENT, KNOWLEDGE_BASE_EXECUTION_ERROR_EVENT, + CREATE_KNOWLEDGE_BASE_ENTRY_SUCCESS_EVENT, + CREATE_KNOWLEDGE_BASE_ENTRY_ERROR_EVENT, INVOKE_ASSISTANT_SUCCESS_EVENT, INVOKE_ASSISTANT_ERROR_EVENT, ATTACK_DISCOVERY_SUCCESS_EVENT, diff --git a/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts b/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts index d5db24d44f3e..e4f520b190b5 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/evaluate/post_evaluate.ts @@ -282,6 +282,7 @@ export const postEvaluateRoute = ( inference, connectorId: connector.id, size, + telemetry: ctx.elasticAssistant.telemetry, }; const tools: StructuredTool[] = assistantTools.flatMap( diff --git a/x-pack/plugins/elastic_assistant/server/routes/helpers.ts b/x-pack/plugins/elastic_assistant/server/routes/helpers.ts index d25ed5fc77f1..0c5c39f77d69 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/helpers.ts @@ -30,6 +30,7 @@ import { ActionsClient } from '@kbn/actions-plugin/server'; import { AssistantFeatureKey } from '@kbn/elastic-assistant-common/impl/capabilities'; import { getLangSmithTracer } from '@kbn/langchain/server/tracers/langsmith'; import type { InferenceServerStart } from '@kbn/inference-plugin/server'; +import { INVOKE_ASSISTANT_SUCCESS_EVENT } from '../lib/telemetry/event_based_telemetry'; import { AIAssistantKnowledgeBaseDataClient } from '../ai_assistant_data_clients/knowledge_base'; import { FindResponse } from '../ai_assistant_data_clients/find'; import { EsPromptsSchema } from '../ai_assistant_data_clients/prompts/types'; @@ -46,7 +47,6 @@ import { executeAction, StaticResponse } from '../lib/executor'; import { getLangChainMessages } from '../lib/langchain/helpers'; import { AIAssistantConversationsDataClient } from '../ai_assistant_data_clients/conversations'; -import { INVOKE_ASSISTANT_SUCCESS_EVENT } from '../lib/telemetry/event_based_telemetry'; import { ElasticAssistantRequestHandlerContext, GetElser } from '../types'; import { callAssistantGraph } from '../lib/langchain/graphs/default_assistant_graph'; @@ -399,6 +399,7 @@ export const langChainExecute = async ({ kbDataClient, }; + const isKnowledgeBaseInstalled = await getIsKnowledgeBaseInstalled(kbDataClient); // Shared executor params const executorParams: AgentExecutorParams = { abortSignal, @@ -422,6 +423,14 @@ export const langChainExecute = async ({ responseLanguage, size: request.body.size, systemPrompt, + telemetry, + telemetryParams: { + actionTypeId, + model: request.body.model, + assistantStreamingEnabled: isStream, + isEnabledKnowledgeBase: isKnowledgeBaseInstalled, + eventType: INVOKE_ASSISTANT_SUCCESS_EVENT.eventType, + }, traceOptions: { projectName: request.body.langSmithProject, tracers: getLangSmithTracer({ @@ -436,14 +445,6 @@ export const langChainExecute = async ({ executorParams ); - const isKnowledgeBaseInstalled = await getIsKnowledgeBaseInstalled(kbDataClient); - - telemetry.reportEvent(INVOKE_ASSISTANT_SUCCESS_EVENT.eventType, { - actionTypeId, - model: request.body.model, - assistantStreamingEnabled: isStream, - isEnabledKnowledgeBase: isKnowledgeBaseInstalled, - }); return response.ok(result); }; diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts index fbe73525578b..fc49068a09cc 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/bulk_actions_route.ts @@ -6,7 +6,7 @@ */ import moment from 'moment'; -import type { IKibanaResponse, KibanaResponseFactory } from '@kbn/core/server'; +import { AnalyticsServiceSetup, IKibanaResponse, KibanaResponseFactory } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { @@ -20,6 +20,7 @@ import { } from '@kbn/elastic-assistant-common'; import { buildRouteValidationWithZod } from '@kbn/elastic-assistant-common/impl/schemas/common'; +import { CREATE_KNOWLEDGE_BASE_ENTRY_SUCCESS_EVENT } from '../../../lib/telemetry/event_based_telemetry'; import { performChecks } from '../../helpers'; import { KNOWLEDGE_BASE_ENTRIES_TABLE_MAX_PAGE_SIZE } from '../../../../common/constants'; import { @@ -62,7 +63,8 @@ const buildBulkResponse = ( created = [], deleted = [], skipped = [], - }: KnowledgeBaseEntryBulkCrudActionResults & { errors: BulkOperationError[] } + }: KnowledgeBaseEntryBulkCrudActionResults & { errors: BulkOperationError[] }, + telemetry: AnalyticsServiceSetup ): IKibanaResponse => { const numSucceeded = updated.length + created.length + deleted.length; const numSkipped = skipped.length; @@ -82,6 +84,16 @@ const buildBulkResponse = ( skipped, }; + if (created.length) { + created.forEach((entry) => { + telemetry.reportEvent(CREATE_KNOWLEDGE_BASE_ENTRY_SUCCESS_EVENT.eventType, { + entryType: entry.type, + required: 'required' in entry ? entry.required ?? false : false, + sharing: entry.users.length ? 'private' : 'global', + ...(entry.type === 'document' ? { source: entry.source } : {}), + }); + }); + } if (numFailed > 0) { return response.custom({ headers: { 'content-type': 'application/json' }, @@ -289,14 +301,18 @@ export const bulkActionKnowledgeBaseEntriesRoute = (router: ElasticAssistantPlug }) : undefined; - return buildBulkResponse(response, { - // @ts-ignore-next-line TS2322 - updated: transformESToKnowledgeBase(docsUpdated), - created: created?.data ? transformESSearchToKnowledgeBaseEntry(created?.data) : [], - deleted: docsDeleted ?? [], - skipped: [], - errors, - }); + return buildBulkResponse( + response, + { + // @ts-ignore-next-line TS2322 + updated: transformESToKnowledgeBase(docsUpdated), + created: created?.data ? transformESSearchToKnowledgeBaseEntry(created?.data) : [], + deleted: docsDeleted ?? [], + skipped: [], + errors, + }, + ctx.elasticAssistant.telemetry + ); } catch (err) { const error = transformError(err); return assistantResponse.error({ diff --git a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts index 0bfe9de269f7..d5df2d02055f 100644 --- a/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts +++ b/x-pack/plugins/elastic_assistant/server/routes/knowledge_base/entries/create_route.ts @@ -65,6 +65,7 @@ export const createKnowledgeBaseEntryRoute = (router: ElasticAssistantPluginRout const createResponse = await kbDataClient?.createKnowledgeBaseEntry({ knowledgeBaseEntry: request.body, global: request.body.users != null && request.body.users.length === 0, + telemetry: ctx.elasticAssistant.telemetry, }); if (createResponse == null) { diff --git a/x-pack/plugins/elastic_assistant/server/types.ts b/x-pack/plugins/elastic_assistant/server/types.ts index e84b97ab43d7..00fec0dcabc6 100755 --- a/x-pack/plugins/elastic_assistant/server/types.ts +++ b/x-pack/plugins/elastic_assistant/server/types.ts @@ -252,4 +252,5 @@ export interface AssistantToolParams { ExecuteConnectorRequestBody | AttackDiscoveryPostRequestBody >; size?: number; + telemetry?: AnalyticsServiceSetup; } diff --git a/x-pack/plugins/elastic_assistant/tsconfig.json b/x-pack/plugins/elastic_assistant/tsconfig.json index d3436f28a1d3..52ed30dde67f 100644 --- a/x-pack/plugins/elastic_assistant/tsconfig.json +++ b/x-pack/plugins/elastic_assistant/tsconfig.json @@ -49,7 +49,8 @@ "@kbn/std", "@kbn/zod", "@kbn/inference-plugin", - "@kbn/data-views-plugin" + "@kbn/data-views-plugin", + "@kbn/core-analytics-server" ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/enterprise_search/kibana.jsonc b/x-pack/plugins/enterprise_search/kibana.jsonc index f631bd2dc53d..14a36c85c6c8 100644 --- a/x-pack/plugins/enterprise_search/kibana.jsonc +++ b/x-pack/plugins/enterprise_search/kibana.jsonc @@ -2,6 +2,9 @@ "type": "plugin", "id": "@kbn/enterprise-search-plugin", "owner": "@elastic/search-kibana", + // Could be categorised as Search in the future, but it currently needs to run in Observability too + "group": "platform", + "visibility": "shared", "description": "Adds dashboards for discovering and managing Enterprise Search products.", "plugin": { "id": "enterpriseSearch", diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/playground/playground.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/playground/playground.tsx index e8e72e5dfb37..c198062cb759 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/playground/playground.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/playground/playground.tsx @@ -15,7 +15,11 @@ import { KibanaLogic } from '../../../shared/kibana'; import { SearchPlaygroundPageTemplate } from './page_template'; -export const Playground: React.FC = () => { +interface PlaygroundProps { + pageMode?: 'chat' | 'search'; +} + +export const Playground: React.FC = ({ pageMode = 'chat' }) => { const { searchPlayground } = useValues(KibanaLogic); if (!searchPlayground) { @@ -35,7 +39,7 @@ export const Playground: React.FC = () => { customPageSections bottomBorder="extended" > - + ); diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/index.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/index.tsx index c9676137e70f..a04ebf2e3edb 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/index.tsx @@ -13,7 +13,13 @@ import { Routes, Route } from '@kbn/shared-ux-router'; import { NotFound } from './components/not_found'; import { Playground } from './components/playground/playground'; import { SearchApplicationsRouter } from './components/search_applications/search_applications_router'; -import { PLAYGROUND_PATH, ROOT_PATH, SEARCH_APPLICATIONS_PATH } from './routes'; +import { + PLAYGROUND_CHAT_PATH, + PLAYGROUND_PATH, + PLAYGROUND_SEARCH_PATH, + ROOT_PATH, + SEARCH_APPLICATIONS_PATH, +} from './routes'; export const Applications = () => { return ( @@ -22,8 +28,12 @@ export const Applications = () => { - - + + + + + + diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/routes.ts b/x-pack/plugins/enterprise_search/public/applications/applications/routes.ts index 5779f544c3f3..2df42a129938 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/routes.ts +++ b/x-pack/plugins/enterprise_search/public/applications/applications/routes.ts @@ -17,7 +17,9 @@ export enum SearchApplicationViewTabs { export const SEARCH_APPLICATION_CREATION_PATH = `${SEARCH_APPLICATIONS_PATH}/new`; export const SEARCH_APPLICATION_PATH = `${SEARCH_APPLICATIONS_PATH}/:searchApplicationName`; export const SEARCH_APPLICATION_TAB_PATH = `${SEARCH_APPLICATION_PATH}/:tabId`; -export const PLAYGROUND_PATH = `${ROOT_PATH}playground`; +export const PLAYGROUND_PATH = `${ROOT_PATH}playground/`; +export const PLAYGROUND_CHAT_PATH = `${PLAYGROUND_PATH}chat`; +export const PLAYGROUND_SEARCH_PATH = `${PLAYGROUND_PATH}search`; export const SEARCH_APPLICATION_CONNECT_PATH = `${SEARCH_APPLICATION_PATH}/${SearchApplicationViewTabs.CONNECT}/:connectTabId`; export enum SearchApplicationConnectTabs { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/manual_configuration.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/manual_configuration.tsx index 825f47920d25..260486a3ec4c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/manual_configuration.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/manual_configuration.tsx @@ -165,7 +165,6 @@ GET connector-${rawName}/_search onClick={() => { setFlyoutContent('manual_config'); setIsFlyoutVisible(true); - closePopover(); }} > {i18n.translate( @@ -206,7 +205,6 @@ GET connector-${rawName}/_search onClick={() => { setFlyoutContent('client'); setIsFlyoutVisible(true); - closePopover(); }} > {i18n.translate( diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/manual_configuration_flyout.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/manual_configuration_flyout.tsx index 98bea7ed62f7..03a633a5aa04 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/manual_configuration_flyout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/manual_configuration_flyout.tsx @@ -27,6 +27,7 @@ import { EuiSpacer, EuiText, EuiTitle, + useEuiTheme, useGeneratedHtmlId, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -68,13 +69,16 @@ export const ManualConfigurationFlyout: React.FC const { connectorName } = useValues(NewConnectorLogic); const { setRawName, createConnector } = useActions(NewConnectorLogic); - + const { euiTheme } = useEuiTheme(); return ( setIsFlyoutVisible(false)} aria-labelledby={simpleFlyoutTitleId} size="s" + // This fixes an a11y issue where the flyout was rendered below the Popover + // Now we let get the focus back to the Popover is we close the Flyout + maskProps={{ style: `z-index: ${Number(euiTheme.levels.menu) + 1}` }} > {flyoutContent === 'manual_config' && ( <> diff --git a/x-pack/plugins/entity_manager/kibana.jsonc b/x-pack/plugins/entity_manager/kibana.jsonc index efd6d3a445b3..d5dadcf8fd2b 100644 --- a/x-pack/plugins/entity_manager/kibana.jsonc +++ b/x-pack/plugins/entity_manager/kibana.jsonc @@ -2,6 +2,8 @@ "type": "plugin", "id": "@kbn/entityManager-plugin", "owner": "@elastic/obs-entities", + "group": "platform", + "visibility": "shared", "description": "Entity manager plugin for entity assets (inventory, topology, etc)", "plugin": { "id": "entityManager", diff --git a/x-pack/plugins/features/server/routes/index.ts b/x-pack/plugins/features/server/routes/index.ts index 281010613f69..b06efbb170ad 100644 --- a/x-pack/plugins/features/server/routes/index.ts +++ b/x-pack/plugins/features/server/routes/index.ts @@ -21,8 +21,12 @@ export function defineRoutes({ router, featureRegistry }: RouteDefinitionParams) router.get( { path: '/api/features', + security: { + authz: { + requiredPrivileges: ['read_features'], + }, + }, options: { - tags: ['access:read_features'], access: 'public', summary: `Get features`, }, diff --git a/x-pack/plugins/fields_metadata/kibana.jsonc b/x-pack/plugins/fields_metadata/kibana.jsonc index 2befc0c7be07..37cdaaf92c2b 100644 --- a/x-pack/plugins/fields_metadata/kibana.jsonc +++ b/x-pack/plugins/fields_metadata/kibana.jsonc @@ -2,6 +2,8 @@ "type": "plugin", "id": "@kbn/fields-metadata-plugin", "owner": "@elastic/obs-ux-logs-team", + "group": "platform", + "visibility": "shared", "description": "Exposes services for async usage and search of fields metadata.", "plugin": { "id": "fieldsMetadata", diff --git a/x-pack/plugins/fleet/common/types/models/output.ts b/x-pack/plugins/fleet/common/types/models/output.ts index 36471c5e95bf..b47a393013ed 100644 --- a/x-pack/plugins/fleet/common/types/models/output.ts +++ b/x-pack/plugins/fleet/common/types/models/output.ts @@ -127,13 +127,6 @@ export interface KafkaOutput extends NewBaseOutput { random?: boolean; }; topic?: string; - topics?: Array<{ - topic: string; - when?: { - type?: ValueOf; - condition?: string; - }; - }>; headers?: Array<{ key: string; value: string; diff --git a/x-pack/plugins/fleet/cypress/screens/fleet_outputs.ts b/x-pack/plugins/fleet/cypress/screens/fleet_outputs.ts index 763e6fae1b1e..5da321c52ba5 100644 --- a/x-pack/plugins/fleet/cypress/screens/fleet_outputs.ts +++ b/x-pack/plugins/fleet/cypress/screens/fleet_outputs.ts @@ -66,7 +66,7 @@ export const kafkaOutputBody = { type: 'kafka', is_default: false, hosts: ['example.com:2000'], - topics: [{ topic: 'test' }], + topic: 'test', auth_type: 'user_pass', username: 'kafka', password: 'kafka', diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx index ff89db3e0c84..db223fee26bf 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx @@ -52,7 +52,7 @@ jest.mock('../../../../hooks', () => { sendGetStatus: jest .fn() .mockResolvedValue({ data: { isReady: true, missing_requirements: [] } }), - sendGetAgentStatus: jest.fn().mockResolvedValue({ data: { results: { total: 0 } } }), + sendGetAgentStatus: jest.fn().mockResolvedValue({ data: { results: { active: 0 } } }), useGetAgentPolicies: jest.fn().mockReturnValue({ data: { items: [ @@ -154,14 +154,7 @@ afterAll(() => { consoleDebugMock.mockRestore(); }); -// FLAKY: https://github.com/elastic/kibana/issues/196463 -// FLAKY: https://github.com/elastic/kibana/issues/196464 -// FLAKY: https://github.com/elastic/kibana/issues/196465 -// FLAKY: https://github.com/elastic/kibana/issues/196466 -// FLAKY: https://github.com/elastic/kibana/issues/196467 -// FLAKY: https://github.com/elastic/kibana/issues/196468 -// FLAKY: https://github.com/elastic/kibana/issues/196469 -describe.skip('When on the package policy create page', () => { +describe('When on the package policy create page', () => { afterEach(() => { jest.clearAllMocks(); }); @@ -534,7 +527,7 @@ describe.skip('When on the package policy create page', () => { (sendCreateAgentPolicy as jest.MockedFunction).mockClear(); (sendCreatePackagePolicy as jest.MockedFunction).mockClear(); (sendGetAgentStatus as jest.MockedFunction).mockResolvedValue({ - data: { results: { total: 0 } }, + data: { results: { active: 0 } }, }); }); @@ -584,7 +577,7 @@ describe.skip('When on the package policy create page', () => { test('should show modal if agent policy has agents', async () => { (sendGetAgentStatus as jest.MockedFunction).mockResolvedValue({ - data: { results: { total: 1 } }, + data: { results: { active: 1 } }, }); await act(async () => { @@ -787,7 +780,7 @@ describe.skip('When on the package policy create page', () => { test('should not show confirmation modal', async () => { (sendGetAgentStatus as jest.MockedFunction).mockResolvedValueOnce({ - data: { results: { total: 1 } }, + data: { results: { active: 1 } }, }); await act(async () => { @@ -854,8 +847,8 @@ describe.skip('When on the package policy create page', () => { expect(sendGetOneAgentPolicy).not.toHaveBeenCalled(); expect(sendCreateAgentPolicy).toHaveBeenCalledWith( expect.objectContaining({ - monitoring_enabled: ['logs', 'metrics', 'traces'], - name: 'Agent policy 1', + monitoring_enabled: ['logs', 'metrics'], + name: 'Agentless policy for nginx-1', }), { withSysMonitoring: true } ); @@ -868,7 +861,7 @@ describe.skip('When on the package policy create page', () => { test('should create agentless agent policy and package policy when in cloud and agentless API url is set', async () => { fireEvent.click(renderResult.getByTestId(SETUP_TECHNOLOGY_SELECTOR_TEST_SUBJ)); - fireEvent.click(renderResult.getByText('Agentless')); + fireEvent.click(renderResult.getAllByText('Agentless')[0]); await act(async () => { fireEvent.click(renderResult.getByText(/Save and continue/).closest('button')!); }); @@ -879,7 +872,7 @@ describe.skip('When on the package policy create page', () => { name: 'Agentless policy for nginx-1', supports_agentless: true, }), - { withSysMonitoring: false } + { withSysMonitoring: true } ); expect(sendCreatePackagePolicy).toHaveBeenCalled(); @@ -894,7 +887,7 @@ describe.skip('When on the package policy create page', () => { const mockApiCalls = (http: MockedFleetStartServices['http']) => { http.get.mockImplementation(async (path: any) => { if (path === '/api/fleet/agents/setup') { - return Promise.resolve({ data: { results: { total: 0 } } }); + return Promise.resolve({ data: { results: { active: 0 } } }); } if (path === '/api/fleet/package_policies') { return Promise.resolve({ data: { items: [] } }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/hooks/use_fetch_agents_data.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/hooks/use_fetch_agents_data.tsx index 35233a5b79fe..e27eb43bfad1 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/hooks/use_fetch_agents_data.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/hooks/use_fetch_agents_data.tsx @@ -52,6 +52,7 @@ function useFullAgentPolicyFetcher() { if (policiesToFetchIds.length) { const bulkGetAgentPoliciesResponse = await sendBulkGetAgentPolicies(policiesToFetchIds, { full: authz.fleet.readAgentPolicies, + ignoreMissing: true, }); if (bulkGetAgentPoliciesResponse.error) { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.test.tsx index e742005a3791..2b343fcdcb57 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.test.tsx @@ -207,7 +207,7 @@ describe('EditOutputFlyout', () => { is_default: false, is_default_monitoring: false, hosts: ['kafka:443'], - topics: [{ topic: 'topic' }], + topic: 'topic', auth_type: 'ssl', version: '1.0.0', ssl: { certificate: 'cert', key: 'key', verification_mode: 'full' }, @@ -247,7 +247,7 @@ describe('EditOutputFlyout', () => { is_default: false, is_default_monitoring: false, hosts: ['kafka:443'], - topics: [{ topic: 'topic' }], + topic: 'topic', auth_type: 'user_pass', version: '1.0.0', username: 'user', diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.test.tsx index cd0b04c33eaf..e088b21a04c0 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.test.tsx @@ -12,7 +12,7 @@ import { describe('use_output_form', () => { describe('extractDefaultDynamicKafkaTopics', () => { - it('should return empty array if not topics are passed', () => { + it('should return empty array if not topic are passed', () => { const res = extractDefaultDynamicKafkaTopics({ type: 'kafka', name: 'new', @@ -23,37 +23,25 @@ describe('use_output_form', () => { expect(res).toEqual([]); }); - it('should return empty array if topics have length == 0', () => { + it('should return empty array if topic do not include %{[', () => { const res = extractDefaultDynamicKafkaTopics({ type: 'kafka', name: 'new', is_default: false, is_default_monitoring: false, - topics: [], + topic: 'something', }); expect(res).toEqual([]); }); - it('should return empty array if topics do not include %{[', () => { + it('should return options for combobox if topic include %{[', () => { const res = extractDefaultDynamicKafkaTopics({ type: 'kafka', name: 'new', is_default: false, is_default_monitoring: false, - topics: [{ topic: 'something' }], - }); - - expect(res).toEqual([]); - }); - - it('should return options for combobox if topics include %{[', () => { - const res = extractDefaultDynamicKafkaTopics({ - type: 'kafka', - name: 'new', - is_default: false, - is_default_monitoring: false, - topics: [{ topic: '%{[default.dataset]}' }], + topic: '%{[default.dataset]}', }); expect(res).toEqual([ @@ -64,13 +52,13 @@ describe('use_output_form', () => { ]); }); - it('should return options for combobox if topics include %{[ and some special characters', () => { + it('should return options for combobox if topic include %{[ and some special characters', () => { const res = extractDefaultDynamicKafkaTopics({ type: 'kafka', name: 'new', is_default: false, is_default_monitoring: false, - topics: [{ topic: '%{[@timestamp]}' }], + topic: '%{[@timestamp]}', }); expect(res).toEqual([ @@ -81,13 +69,13 @@ describe('use_output_form', () => { ]); }); - it('should return options for combobox if topics include %{[ and a custom name', () => { + it('should return options for combobox if topic include %{[ and a custom name', () => { const res = extractDefaultDynamicKafkaTopics({ type: 'kafka', name: 'new', is_default: false, is_default_monitoring: false, - topics: [{ topic: '%{[something]}' }], + topic: '%{[something]}', }); expect(res).toEqual([ @@ -100,7 +88,7 @@ describe('use_output_form', () => { }); describe('extractDefaultStaticKafkaTopic', () => { - it('should return empty array if not topics are passed', () => { + it('should return empty array if not topic are passed', () => { const res = extractDefaultStaticKafkaTopic({ type: 'kafka', name: 'new', @@ -111,52 +99,28 @@ describe('use_output_form', () => { expect(res).toEqual(''); }); - it('should return empty array if topics have length == 0', () => { + it('should return empty string if topic include %{[', () => { const res = extractDefaultStaticKafkaTopic({ type: 'kafka', name: 'new', is_default: false, is_default_monitoring: false, - topics: [], + topic: '%{[something]}', }); expect(res).toEqual(''); }); - it('should return empty string if topics include %{[', () => { + it('should return the topic if topic field is defined', () => { const res = extractDefaultStaticKafkaTopic({ type: 'kafka', name: 'new', is_default: false, is_default_monitoring: false, - topics: [{ topic: '%{[something]}' }], - }); - - expect(res).toEqual(''); - }); - - it('should return the topic if topics field is defined', () => { - const res = extractDefaultStaticKafkaTopic({ - type: 'kafka', - name: 'new', - is_default: false, - is_default_monitoring: false, - topics: [{ topic: 'something' }], + topic: 'something', }); expect(res).toEqual('something'); }); - - it('should return the last topic if topics field is defined and has multiple', () => { - const res = extractDefaultStaticKafkaTopic({ - type: 'kafka', - name: 'new', - is_default: false, - is_default_monitoring: false, - topics: [{ topic: 'something_1' }, { topic: 'something_2' }, { topic: 'something_3' }], - }); - - expect(res).toEqual('something_3'); - }); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx index 8526fcdae001..e47e27187230 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/use_output_form.tsx @@ -162,25 +162,20 @@ function extractKafkaOutputSecrets( } export function extractDefaultStaticKafkaTopic(o: KafkaOutput): string { - if ( - !o?.topics || - o.topics?.length === 0 || - (o.topics && o?.topics.length > 0 && o.topics[0].topic?.includes('%{[')) - ) { + if (o?.topic?.includes('%{[')) { return ''; } - const lastTopic = o.topics[o.topics.length - 1].topic; - return lastTopic || ''; + return o?.topic || ''; } export function extractDefaultDynamicKafkaTopics( o: KafkaOutput ): Array> { - if (!o?.topics || o.topics?.length === 0 || (o.topics && !o.topics[0]?.topic?.includes('%{['))) { + if (!o?.topic || (o?.topic && !o.topic?.includes('%{['))) { return []; } - const matched = o.topics[0].topic.match(/(%\{\[)(\S*)(\]\})/); + const matched = o.topic.match(/(%\{\[)(\S*)(\]\})/); const parsed = matched?.length ? matched[2] : ''; return [ @@ -470,23 +465,23 @@ export function useOutputForm(onSucess: () => void, output?: Output, defaultOupu ); const kafkaTopicsInput = useRadioInput( - kafkaOutput?.topics && kafkaOutput?.topics[0].topic?.includes('%{[') + kafkaOutput?.topic && kafkaOutput?.topic?.includes('%{[') ? kafkaTopicsType.Dynamic : kafkaTopicsType.Static, - isDisabled('topics') + isDisabled('topic') ); const kafkaStaticTopicInput = useInput( extractDefaultStaticKafkaTopic(kafkaOutput), kafkaTopicsInput.value === kafkaTopicsType.Static ? validateKafkaStaticTopic : undefined, - isDisabled('topics') + isDisabled('topic') ); const kafkaDynamicTopicInput = useComboBoxWithCustomInput( 'kafkaDynamicTopicComboBox', extractDefaultDynamicKafkaTopics(kafkaOutput), kafkaTopicsInput.value === kafkaTopicsType.Dynamic ? validateDynamicKafkaTopics : undefined, - isDisabled('topics') + isDisabled('topic') ); const kafkaHeadersInput = useKeyValueInput( @@ -874,19 +869,11 @@ export function useOutputForm(onSucess: () => void, output?: Output, defaultOupu : {}), ...(kafkaTopicsInput.value === kafkaTopicsType.Static && kafkaStaticTopicInput.value ? { - topics: [ - { - topic: kafkaStaticTopicInput.value, - }, - ], + topic: kafkaStaticTopicInput.value, } : kafkaTopicsInput.value === kafkaTopicsType.Dynamic && kafkaDynamicTopicInput.value ? { - topics: [ - { - topic: `%{[${kafkaDynamicTopicInput.value}]}`, - }, - ], + topic: `%{[${kafkaDynamicTopicInput.value}]}`, } : {}), headers: kafkaHeadersInput.value, diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/documentation/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/documentation/index.tsx index a418c38cd8f3..c4fc2863868a 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/documentation/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/documentation/index.tsx @@ -79,7 +79,7 @@ export const DocumentationPage: React.FunctionComponent = ({ packageInfo, defaultMessage="This documents all the inputs, streams, and variables available to use this integration programmatically via the Fleet Kibana API. {learnMore}" values={{ learnMore: ( - +
    {children}
    , h6: ({ children }) =>
    {children}
    , - link: ({ children, href }: { children: React.ReactNode[]; href?: string }) => ( + a: ({ children, href }: { children: React.ReactNode[]; href?: string }) => ( { +describe('Fleet cloud preconfiguration', () => { let esServer: TestElasticsearchUtils; let kbnServer: TestKibanaUtils; diff --git a/x-pack/plugins/fleet/server/integration_tests/fixtures/cloud_kibana_config.ts b/x-pack/plugins/fleet/server/integration_tests/fixtures/cloud_kibana_config.ts index fa9770a58f44..da1a0a9a6838 100644 --- a/x-pack/plugins/fleet/server/integration_tests/fixtures/cloud_kibana_config.ts +++ b/x-pack/plugins/fleet/server/integration_tests/fixtures/cloud_kibana_config.ts @@ -8,6 +8,11 @@ export const CLOUD_KIBANA_CONFIG = { xpack: { fleet: { + internal: { + registry: { + kibanaVersionCheckEnabled: false, + }, + }, packages: [ { name: 'apm', diff --git a/x-pack/plugins/fleet/server/integration_tests/ha_setup.test.ts b/x-pack/plugins/fleet/server/integration_tests/ha_setup.test.ts index c0405b2523fa..1d34153fab26 100644 --- a/x-pack/plugins/fleet/server/integration_tests/ha_setup.test.ts +++ b/x-pack/plugins/fleet/server/integration_tests/ha_setup.test.ts @@ -91,7 +91,7 @@ const createAndSetupRoot = async (config?: object) => { * Verifies that multiple Kibana instances running in parallel will not create duplicate preconfiguration objects. */ // Failing 9.0 version update: https://github.com/elastic/kibana/issues/192624 -describe.skip('Fleet setup preconfiguration with multiple instances Kibana', () => { +describe('Fleet setup preconfiguration with multiple instances Kibana', () => { let esServer: TestElasticsearchUtils; // let esClient: Client; let roots: Root[] = []; @@ -175,6 +175,11 @@ describe.skip('Fleet setup preconfiguration with multiple instances Kibana', () const preconfiguration = { registryUrl, + internal: { + registry: { + kibanaVersionCheckEnabled: false, + }, + }, packages: [ { name: 'fleet_server', diff --git a/x-pack/plugins/fleet/server/integration_tests/reset_preconfiguration.test.ts b/x-pack/plugins/fleet/server/integration_tests/reset_preconfiguration.test.ts index b3d9b65a1f3e..65224e2408bd 100644 --- a/x-pack/plugins/fleet/server/integration_tests/reset_preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/integration_tests/reset_preconfiguration.test.ts @@ -23,7 +23,7 @@ import { useDockerRegistry, waitForFleetSetup, getSupertestWithAdminUser } from const logFilePath = Path.join(__dirname, 'logs.log'); // Failing 9.0 version update: https://github.com/elastic/kibana/issues/192624 -describe.skip('Fleet preconfiguration reset', () => { +describe('Fleet preconfiguration reset', () => { let esServer: TestElasticsearchUtils; let kbnServer: TestKibanaUtils; @@ -47,6 +47,11 @@ describe.skip('Fleet preconfiguration reset', () => { xpack: { fleet: { registryUrl, + internal: { + registry: { + kibanaVersionCheckEnabled: false, + }, + }, packages: [ { name: 'fleet_server', @@ -253,7 +258,7 @@ describe.skip('Fleet preconfiguration reset', () => { ); await resetAPI .set('kbn-sxrf', 'xx') - .set('Elastic-Api-Version', `${API_VERSIONS.internal.v1}`) + .set('Elastic-Api-Version', `${API_VERSIONS.public.v1}`) .expect(200) .send(); @@ -298,7 +303,7 @@ describe.skip('Fleet preconfiguration reset', () => { ); await resetAPI .set('kbn-sxrf', 'xx') - .set('Elastic-Api-Version', `${API_VERSIONS.internal.v1}`) + .set('Elastic-Api-Version', `${API_VERSIONS.public.v1}`) .expect(200) .send(); @@ -336,7 +341,7 @@ describe.skip('Fleet preconfiguration reset', () => { ); await resetAPI .set('kbn-sxrf', 'xx') - .set('Elastic-Api-Version', `${API_VERSIONS.internal.v1}`) + .set('Elastic-Api-Version', `${API_VERSIONS.public.v1}`) .expect(200) .send(); @@ -373,7 +378,7 @@ describe.skip('Fleet preconfiguration reset', () => { ); await resetAPI .set('kbn-sxrf', 'xx') - .set('Elastic-Api-Version', `${API_VERSIONS.internal.v1}`) + .set('Elastic-Api-Version', `${API_VERSIONS.public.v1}`) .expect(200) .send(); diff --git a/x-pack/plugins/fleet/server/routes/agent/index.ts b/x-pack/plugins/fleet/server/routes/agent/index.ts index 1c40f36a7e48..cc1550fe2468 100644 --- a/x-pack/plugins/fleet/server/routes/agent/index.ts +++ b/x-pack/plugins/fleet/server/routes/agent/index.ts @@ -97,7 +97,8 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { readAgents: true }, }, - description: `Get agent by ID`, + summary: `Get an agent`, + description: `Get an agent by ID.`, options: { tags: ['oas-tag:Elastic Agents'], }, @@ -127,7 +128,8 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { allAgents: true }, }, - description: `Update agent by ID`, + summary: `Update an agent`, + description: `Update an agent by ID.`, options: { tags: ['oas-tag:Elastic Agents'], }, @@ -157,7 +159,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { allAgents: true }, }, - description: `Bulk update agent tags`, + summary: `Bulk update agent tags`, options: { tags: ['oas-tag:Elastic Agent actions'], }, @@ -187,7 +189,8 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { allAgents: true }, }, - description: `Delete agent by ID`, + summary: `Delete an agent`, + description: `Delete an agent by ID.`, options: { tags: ['oas-tag:Elastic Agents'], }, @@ -218,7 +221,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { readAgents: true }, }, - description: `List agents`, + summary: `Get agents`, options: { tags: ['oas-tag:Elastic Agents'], }, @@ -248,7 +251,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { readAgents: true }, }, - description: `List agent tags`, + summary: `Get agent tags`, options: { tags: ['oas-tag:Elastic Agents'], }, @@ -278,7 +281,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { allAgents: true }, }, - description: `Create agent action`, + summary: `Create an agent action`, options: { tags: ['oas-tag:Elastic Agent actions'], }, @@ -312,7 +315,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { allAgents: true }, }, - description: `Cancel agent action`, + summary: `Cancel an agent action`, options: { tags: ['oas-tag:Elastic Agent actions'], }, @@ -347,7 +350,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { readAgents: true }, }, - description: `List agents by action ids`, + summary: `Get agents by action ids`, options: { tags: ['oas-tag:Elastic Agents'], }, @@ -376,7 +379,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { allAgents: true }, }, - description: `Unenroll agent`, + summary: `Unenroll an agent`, options: { tags: ['oas-tag:Elastic Agent actions'], }, @@ -395,7 +398,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { allAgents: true }, }, - description: `Reassign agent`, + summary: `Reassign an agent`, options: { tags: ['oas-tag:Elastic Agent actions'], }, @@ -424,7 +427,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { readAgents: true }, }, - description: `Request agent diagnostics`, + summary: `Request agent diagnostics`, options: { tags: ['oas-tag:Elastic Agent actions'], }, @@ -453,7 +456,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { readAgents: true }, }, - description: `Bulk request diagnostics from agents`, + summary: `Bulk request diagnostics from agents`, options: { tags: ['oas-tag:Elastic Agent actions'], }, @@ -482,7 +485,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { readAgents: true }, }, - description: `List agent uploads`, + summary: `Get agent uploads`, options: { tags: ['oas-tag:Elastic Agents'], }, @@ -511,7 +514,8 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { readAgents: true }, }, - description: `Get file uploaded by agent`, + summary: `Get an uploaded file`, + description: `Get a file uploaded by an agent.`, options: { tags: ['oas-tag:Elastic Agents'], }, @@ -540,7 +544,8 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { allAgents: true }, }, - description: `Delete file uploaded by agent`, + summary: `Delete an uploaded file`, + description: `Delete a file uploaded by an agent.`, options: { tags: ['oas-tag:Elastic Agents'], }, @@ -572,7 +577,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz, getRouteRequiredAuthz('get', AGENT_API_ROUTES.STATUS_PATTERN) ).granted, - description: `Get agent status summary`, + summary: `Get an agent status summary`, options: { tags: ['oas-tag:Elastic Agent status'], }, @@ -601,7 +606,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { readAgents: true }, }, - description: `Get incoming agent data`, + summary: `Get incoming agent data`, options: { tags: ['oas-tag:Elastic Agents'], }, @@ -631,7 +636,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { allAgents: true }, }, - description: `Upgrade agent`, + summary: `Upgrade an agent`, options: { tags: ['oas-tag:Elastic Agent actions'], }, @@ -660,7 +665,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { allAgents: true }, }, - description: `Bulk upgrade agents`, + summary: `Bulk upgrade agents`, options: { tags: ['oas-tag:Elastic Agent actions'], }, @@ -690,7 +695,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { readAgents: true }, }, - description: `Get agent action status`, + summary: `Get an agent action status`, options: { tags: ['oas-tag:Elastic Agent actions'], }, @@ -720,7 +725,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { allAgents: true }, }, - description: `Bulk reassign agents`, + summary: `Bulk reassign agents`, options: { tags: ['oas-tag:Elastic Agent actions'], }, @@ -750,7 +755,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { allAgents: true }, }, - description: `Bulk unenroll agents`, + summary: `Bulk unenroll agents`, options: { tags: ['oas-tag:Elastic Agent actions'], }, @@ -780,7 +785,7 @@ export const registerAPIRoutes = (router: FleetAuthzRouter, config: FleetConfigT fleetAuthz: { fleet: { readAgents: true }, }, - description: `Get available agent versions`, + summary: `Get available agent versions`, options: { tags: ['oas-tag:Elastic Agents'], }, diff --git a/x-pack/plugins/fleet/server/routes/agent_policy/index.ts b/x-pack/plugins/fleet/server/routes/agent_policy/index.ts index 9311f0ae2acc..0d0dc6ae68c2 100644 --- a/x-pack/plugins/fleet/server/routes/agent_policy/index.ts +++ b/x-pack/plugins/fleet/server/routes/agent_policy/index.ts @@ -64,7 +64,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { // Allow to retrieve agent policies metadata (no full) for user with only read agents permissions return authz.fleet.readAgentPolicies || authz.fleet.readAgents; }, - description: `List agent policies`, + summary: `Get agent policies`, options: { tags: ['oas-tag:Elastic Agent policies'], }, @@ -95,7 +95,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { // Allow to retrieve agent policies metadata (no full) for user with only read agents permissions return authz.fleet.readAgentPolicies || authz.fleet.readAgents; }, - description: `Bulk get agent policies`, + summary: `Bulk get agent policies`, options: { tags: ['oas-tag:Elastic Agent policies'], }, @@ -126,7 +126,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { // Allow to retrieve agent policies metadata (no full) for user with only read agents permissions return authz.fleet.readAgentPolicies || authz.fleet.readAgents; }, - description: `Get an agent policy by ID`, + summary: `Get an agent policy`, + description: `Get an agent policy by ID.`, options: { tags: ['oas-tag:Elastic Agent policies'], }, @@ -156,7 +157,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allAgentPolicies: true }, }, - description: `Create an agent policy`, + summary: `Create an agent policy`, options: { tags: ['oas-tag:Elastic Agent policies'], }, @@ -186,7 +187,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allAgentPolicies: true }, }, - description: `Update an agent policy by ID`, + summary: `Update an agent policy`, + description: `Update an agent policy by ID.`, options: { tags: ['oas-tag:Elastic Agent policies'], }, @@ -216,7 +218,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allAgentPolicies: true }, }, - description: `Copy an agent policy by ID`, + summary: `Copy an agent policy`, + description: `Copy an agent policy by ID.`, options: { tags: ['oas-tag:Elastic Agent policies'], }, @@ -246,7 +249,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allAgentPolicies: true }, }, - description: `Delete agent policy by ID`, + summary: `Delete an agent policy`, + description: `Delete an agent policy by ID.`, options: { tags: ['oas-tag:Elastic Agent policies'], }, @@ -276,7 +280,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { readAgentPolicies: true }, }, - description: `Get a full agent policy by ID`, + summary: `Get a full agent policy`, + description: `Get a full agent policy by ID.`, options: { tags: ['oas-tag:Elastic Agent policies'], }, @@ -307,7 +312,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleet: { readAgentPolicies: true }, }, enableQueryVersion: true, - description: `Download an agent policy by ID`, + summary: `Download an agent policy`, + description: `Download an agent policy by ID.`, options: { tags: ['oas-tag:Elastic Agent policies'], }, @@ -340,7 +346,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { readAgentPolicies: true }, }, - description: `Get full K8s agent manifest`, + summary: `Get a full K8s agent manifest`, options: { tags: ['oas-tag:Elastic Agent policies'], }, @@ -371,7 +377,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleet: { readAgentPolicies: true }, }, enableQueryVersion: true, - description: ``, + summary: `Download an agent manifest`, options: { tags: ['oas-tag:Elastic Agent policies'], }, @@ -403,7 +409,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: (authz) => { return authz.fleet.readAgentPolicies && authz.fleet.readSettings; }, - description: `Get list of outputs associated with agent policies`, + summary: `Get outputs for agent policies`, + description: `Get a list of outputs associated with agent policies.`, options: { tags: ['oas-tag:Elastic Agent policies'], }, @@ -432,7 +439,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: (authz) => { return authz.fleet.readAgentPolicies && authz.fleet.readSettings; }, - description: `Get list of outputs associated with agent policy by policy id`, + summary: `Get outputs for an agent policy`, + description: `Get a list of outputs associated with agent policy by policy id.`, options: { tags: ['oas-tag:Elastic Agent policies'], }, diff --git a/x-pack/plugins/fleet/server/routes/app/index.ts b/x-pack/plugins/fleet/server/routes/app/index.ts index e66f9f02a687..db7eddd5ddd4 100644 --- a/x-pack/plugins/fleet/server/routes/app/index.ts +++ b/x-pack/plugins/fleet/server/routes/app/index.ts @@ -218,7 +218,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType router.versioned .get({ path: APP_API_ROUTES.CHECK_PERMISSIONS_PATTERN, - description: `Check permissions`, + summary: `Check permissions`, options: { tags: ['oas-tag:Fleet internals'], }, @@ -263,7 +263,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: { fleet: { allAgents: true }, }, - description: `Create a service token`, + summary: `Create a service token`, options: { tags: ['oas-tag:Fleet service tokens'], }, diff --git a/x-pack/plugins/fleet/server/routes/data_streams/index.ts b/x-pack/plugins/fleet/server/routes/data_streams/index.ts index a20b893717fd..7dc870c394bc 100644 --- a/x-pack/plugins/fleet/server/routes/data_streams/index.ts +++ b/x-pack/plugins/fleet/server/routes/data_streams/index.ts @@ -52,7 +52,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { all: true }, }, - description: `List data streams`, + summary: `Get data streams`, options: { tags: ['oas-tag:Data streams'], }, diff --git a/x-pack/plugins/fleet/server/routes/download_source/index.ts b/x-pack/plugins/fleet/server/routes/download_source/index.ts index 83059593730d..687fdcf5f793 100644 --- a/x-pack/plugins/fleet/server/routes/download_source/index.ts +++ b/x-pack/plugins/fleet/server/routes/download_source/index.ts @@ -39,7 +39,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: (authz) => { return authz.fleet.readSettings || authz.fleet.readAgentPolicies; }, - description: `List agent binary download sources`, + summary: `Get agent binary download sources`, options: { tags: ['oas-tag:Elastic Agent binary download sources'], }, @@ -68,7 +68,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: (authz) => { return authz.fleet.readSettings || authz.fleet.readAgentPolicies; }, - description: `Get agent binary download source by ID`, + summary: `Get an agent binary download source`, + description: `Get an agent binary download source by ID.`, options: { tags: ['oas-tag:Elastic Agent binary download sources'], }, @@ -97,7 +98,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allSettings: true }, }, - description: `Update agent binary download source by ID`, + summary: `Update an agent binary download source`, + description: `Update an agent binary download source by ID.`, options: { tags: ['oas-tag:Elastic Agent binary download sources'], }, @@ -126,7 +128,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allSettings: true }, }, - description: `Create agent binary download source`, + summary: `Create an agent binary download source`, options: { tags: ['oas-tag:Elastic Agent binary download sources'], }, @@ -155,7 +157,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allSettings: true }, }, - description: `Delete agent binary download source by ID`, + summary: `Delete an agent binary download source`, + description: `Delete an agent binary download source by ID.`, options: { tags: ['oas-tag:Elastic Agent binary download sources'], }, diff --git a/x-pack/plugins/fleet/server/routes/enrollment_api_key/index.ts b/x-pack/plugins/fleet/server/routes/enrollment_api_key/index.ts index bc6c61dc8ffe..58538ba18f35 100644 --- a/x-pack/plugins/fleet/server/routes/enrollment_api_key/index.ts +++ b/x-pack/plugins/fleet/server/routes/enrollment_api_key/index.ts @@ -39,7 +39,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { readEnrollmentTokens: true }, }, - description: `Get enrollment API key by ID`, + summary: `Get an enrollment API key`, + description: `Get an enrollment API key by ID.`, options: { tags: ['oas-tag:Fleet enrollment API keys'], }, @@ -68,7 +69,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allAgents: true }, }, - description: `Revoke enrollment API key by ID by marking it as inactive`, + summary: `Revoke an enrollment API key`, + description: `Revoke an enrollment API key by ID by marking it as inactive.`, options: { tags: ['oas-tag:Fleet enrollment API keys'], }, @@ -97,7 +99,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { readEnrollmentTokens: true }, }, - description: `List enrollment API keys`, + summary: `Get enrollment API keys`, options: { tags: ['oas-tag:Fleet enrollment API keys'], }, @@ -126,7 +128,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allAgents: true }, }, - description: `Create enrollment API key`, + summary: `Create an enrollment API key`, options: { tags: ['oas-tag:Fleet enrollment API keys'], }, diff --git a/x-pack/plugins/fleet/server/routes/epm/index.ts b/x-pack/plugins/fleet/server/routes/epm/index.ts index 283f8d6a1b0a..787b02b69c3e 100644 --- a/x-pack/plugins/fleet/server/routes/epm/index.ts +++ b/x-pack/plugins/fleet/server/routes/epm/index.ts @@ -102,7 +102,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType .get({ path: EPM_API_ROUTES.CATEGORIES_PATTERN, fleetAuthz: READ_PACKAGE_INFO_AUTHZ, - description: `List package categories`, + summary: `Get package categories`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -129,7 +129,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType .get({ path: EPM_API_ROUTES.LIST_PATTERN, fleetAuthz: READ_PACKAGE_INFO_AUTHZ, - description: `List packages`, + summary: `Get packages`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -156,7 +156,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType .get({ path: EPM_API_ROUTES.INSTALLED_LIST_PATTERN, fleetAuthz: READ_PACKAGE_INFO_AUTHZ, - description: `Get installed packages`, + summary: `Get installed packages`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -183,7 +183,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType .get({ path: EPM_API_ROUTES.LIMITED_LIST_PATTERN, fleetAuthz: READ_PACKAGE_INFO_AUTHZ, - description: `Get limited package list`, + summary: `Get a limited package list`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -210,7 +210,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType .get({ path: EPM_API_ROUTES.STATS_PATTERN, fleetAuthz: READ_PACKAGE_INFO_AUTHZ, - description: `Get package stats`, + summary: `Get package stats`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -237,7 +237,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType .get({ path: EPM_API_ROUTES.INPUTS_PATTERN, fleetAuthz: READ_PACKAGE_INFO_AUTHZ, - description: `Get inputs template`, + summary: `Get an inputs template`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -264,7 +264,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType .get({ path: EPM_API_ROUTES.FILEPATH_PATTERN, fleetAuthz: READ_PACKAGE_INFO_AUTHZ, - description: `Get package file`, + summary: `Get a package file`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -293,7 +293,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: (fleetAuthz: FleetAuthz): boolean => calculateRouteAuthz(fleetAuthz, getRouteRequiredAuthz('get', EPM_API_ROUTES.INFO_PATTERN)) .granted, - description: `Get package`, + summary: `Get a package`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -322,7 +322,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: { integrations: { writePackageSettings: true }, }, - description: `Update package settings`, + summary: `Update package settings`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -349,7 +349,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType .post({ path: EPM_API_ROUTES.INSTALL_FROM_REGISTRY_PATTERN, fleetAuthz: INSTALL_PACKAGES_AUTHZ, - description: `Install package from registry`, + summary: `Install a package from the registry`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -379,7 +379,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: { integrations: { installPackages: true }, }, - description: `Install Kibana assets for package`, + summary: `Install Kibana assets for a package`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -408,7 +408,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: { integrations: { installPackages: true }, }, - description: `Delete Kibana assets for package`, + summary: `Delete Kibana assets for a package`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -438,7 +438,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: { integrations: { installPackages: true, upgradePackages: true }, }, - description: `Bulk install packages`, + summary: `Bulk install packages`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -476,7 +476,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: { integrations: { uploadPackages: true }, }, - description: `Install package by upload`, + summary: `Install a package by upload`, }) .addVersion( { @@ -500,7 +500,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType .post({ path: EPM_API_ROUTES.CUSTOM_INTEGRATIONS_PATTERN, fleetAuthz: INSTALL_PACKAGES_AUTHZ, - description: `Create custom integration`, + summary: `Create a custom integration`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -529,7 +529,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: { integrations: { removePackages: true }, }, - description: `Delete package`, + summary: `Delete a package`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -557,7 +557,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType .get({ path: EPM_API_ROUTES.VERIFICATION_KEY_ID, fleetAuthz: READ_PACKAGE_INFO_AUTHZ, - description: `Get a package signature verification key ID`, + summary: `Get a package signature verification key ID`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -584,7 +584,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType .get({ path: EPM_API_ROUTES.DATA_STREAMS_PATTERN, fleetAuthz: READ_PACKAGE_INFO_AUTHZ, - description: `List data streams`, + summary: `Get data streams`, options: { tags: ['oas-tag:Data streams'], }, @@ -611,7 +611,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType .post({ path: EPM_API_ROUTES.BULK_ASSETS_PATTERN, fleetAuthz: READ_PACKAGE_INFO_AUTHZ, - description: `Bulk get assets`, + summary: `Bulk get assets`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, @@ -651,7 +651,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType }, }, }, - description: `Authorize transforms`, + summary: `Authorize transforms`, options: { tags: ['oas-tag:Elastic Package Manager (EPM)'], }, diff --git a/x-pack/plugins/fleet/server/routes/fleet_proxies/index.ts b/x-pack/plugins/fleet/server/routes/fleet_proxies/index.ts index 54eba070dd8e..1a5ad6ccc764 100644 --- a/x-pack/plugins/fleet/server/routes/fleet_proxies/index.ts +++ b/x-pack/plugins/fleet/server/routes/fleet_proxies/index.ts @@ -37,7 +37,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { readSettings: true }, }, - description: `List proxies`, + summary: `Get proxies`, options: { tags: ['oas-tag:Fleet proxies'], }, @@ -66,7 +66,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allSettings: true }, }, - description: `Create proxy`, + summary: `Create a proxy`, options: { tags: ['oas-tag:Fleet proxies'], }, @@ -95,7 +95,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allSettings: true }, }, - description: `Update proxy by ID`, + summary: `Update a proxy`, + description: `Update a proxy by ID.`, options: { tags: ['oas-tag:Fleet proxies'], }, @@ -124,7 +125,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { readSettings: true }, }, - description: `Get proxy by ID`, + summary: `Get a proxy`, + description: `Get a proxy by ID.`, options: { tags: ['oas-tag:Fleet proxies'], }, @@ -153,7 +155,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allSettings: true }, }, - description: `Delete proxy by ID`, + summary: `Delete a proxy`, + description: `Delete a proxy by ID`, options: { tags: ['oas-tag:Fleet proxies'], }, diff --git a/x-pack/plugins/fleet/server/routes/fleet_server_hosts/index.ts b/x-pack/plugins/fleet/server/routes/fleet_server_hosts/index.ts index 0a79e9ae1164..667a61765949 100644 --- a/x-pack/plugins/fleet/server/routes/fleet_server_hosts/index.ts +++ b/x-pack/plugins/fleet/server/routes/fleet_server_hosts/index.ts @@ -39,7 +39,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: (authz) => { return authz.fleet.addAgents || authz.fleet.addFleetServers || authz.fleet.readSettings; }, - description: `List Fleet Server hosts`, + summary: `Get Fleet Server hosts`, options: { tags: ['oas-tag:Fleet Server hosts'], }, @@ -67,7 +67,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allSettings: true }, }, - description: `Create Fleet Server host`, + summary: `Create a Fleet Server host`, options: { tags: ['oas-tag:Fleet Server hosts'], }, @@ -95,7 +95,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { readSettings: true }, }, - description: `Get Fleet Server host by ID`, + summary: `Get a Fleet Server host`, + description: `Get a Fleet Server host by ID.`, options: { tags: ['oas-tag:Fleet Server hosts'], }, @@ -123,7 +124,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allSettings: true }, }, - description: `Delete Fleet Server host by ID`, + summary: `Delete a Fleet Server host`, + description: `Delete a Fleet Server host by ID.`, options: { tags: ['oas-tag:Fleet Server hosts'], }, @@ -154,7 +156,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allSettings: true }, }, - description: `Update Fleet Server host by ID`, + summary: `Update a Fleet Server host`, + description: `Update a Fleet Server host by ID.`, options: { tags: ['oas-tag:Fleet Server hosts'], }, diff --git a/x-pack/plugins/fleet/server/routes/health_check/index.ts b/x-pack/plugins/fleet/server/routes/health_check/index.ts index 3b06526b62d1..008340d00682 100644 --- a/x-pack/plugins/fleet/server/routes/health_check/index.ts +++ b/x-pack/plugins/fleet/server/routes/health_check/index.ts @@ -22,7 +22,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allSettings: true }, }, - description: `Check Fleet Server health`, + summary: `Check Fleet Server health`, options: { tags: ['oas-tag:Fleet internals'], }, diff --git a/x-pack/plugins/fleet/server/routes/message_signing_service/index.ts b/x-pack/plugins/fleet/server/routes/message_signing_service/index.ts index 4e78b3228df5..645e7070f901 100644 --- a/x-pack/plugins/fleet/server/routes/message_signing_service/index.ts +++ b/x-pack/plugins/fleet/server/routes/message_signing_service/index.ts @@ -23,7 +23,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { all: true }, }, - description: 'Rotate fleet message signing key pair', + summary: 'Rotate a Fleet message signing key pair', options: { tags: ['oas-tag:Message Signing Service'], }, diff --git a/x-pack/plugins/fleet/server/routes/output/index.ts b/x-pack/plugins/fleet/server/routes/output/index.ts index c9d5b6acdd7d..dd89eaabf396 100644 --- a/x-pack/plugins/fleet/server/routes/output/index.ts +++ b/x-pack/plugins/fleet/server/routes/output/index.ts @@ -43,7 +43,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: (authz) => { return authz.fleet.readSettings || authz.fleet.readAgentPolicies; }, - description: 'List outputs', + summary: 'Get outputs', options: { tags: ['oas-tag:Fleet outputs'], }, @@ -71,7 +71,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: (authz) => { return authz.fleet.readSettings || authz.fleet.readAgentPolicies; }, - description: 'Get output by ID', + summary: 'Get output', + description: 'Get output by ID.', options: { tags: ['oas-tag:Fleet outputs'], }, @@ -99,7 +100,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: (authz) => { return authz.fleet.allSettings || authz.fleet.allAgentPolicies; }, - description: 'Update output by ID', + summary: 'Update output', + description: 'Update output by ID.', options: { tags: ['oas-tag:Fleet outputs'], }, @@ -128,7 +130,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allSettings: true }, }, - description: 'Create output', + summary: 'Create output', options: { tags: ['oas-tag:Fleet outputs'], }, @@ -157,7 +159,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allSettings: true }, }, - description: 'Delete output by ID', + summary: 'Delete output', + description: 'Delete output by ID.', options: { tags: ['oas-tag:Fleet outputs'], }, @@ -189,7 +192,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { allSettings: true }, }, - description: 'Generate Logstash API key', + summary: 'Generate a Logstash API key', options: { tags: ['oas-tag:Fleet outputs'], }, @@ -218,7 +221,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { readSettings: true }, }, - description: 'Get latest output health', + summary: 'Get the latest output health', options: { tags: ['oas-tag:Fleet outputs'], }, diff --git a/x-pack/plugins/fleet/server/routes/package_policy/index.ts b/x-pack/plugins/fleet/server/routes/package_policy/index.ts index 86ac38e658ee..8a547f4127f9 100644 --- a/x-pack/plugins/fleet/server/routes/package_policy/index.ts +++ b/x-pack/plugins/fleet/server/routes/package_policy/index.ts @@ -61,7 +61,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz, getRouteRequiredAuthz('get', PACKAGE_POLICY_API_ROUTES.LIST_PATTERN) ).granted, - description: 'List package policies', + summary: 'Get package policies', options: { tags: ['oas-tag:Fleet package policies'], }, @@ -93,7 +93,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz, getRouteRequiredAuthz('post', PACKAGE_POLICY_API_ROUTES.BULK_GET_PATTERN) ).granted, - description: 'Bulk get package policies', + summary: 'Bulk get package policies', options: { tags: ['oas-tag:Fleet package policies'], }, @@ -128,7 +128,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz, getRouteRequiredAuthz('get', PACKAGE_POLICY_API_ROUTES.INFO_PATTERN) ).granted, - description: 'Get package policy by ID', + summary: 'Get a package policy', + description: 'Get a package policy by ID.', options: { tags: ['oas-tag:Fleet package policies'], }, @@ -187,7 +188,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { router.versioned .post({ path: PACKAGE_POLICY_API_ROUTES.CREATE_PATTERN, - description: 'Create package policy', + summary: 'Create a package policy', options: { tags: ['oas-tag:Fleet package policies'], }, @@ -222,7 +223,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz, getRouteRequiredAuthz('put', PACKAGE_POLICY_API_ROUTES.UPDATE_PATTERN) ).granted, - description: 'Update package policy by ID', + summary: 'Update a package policy', + description: 'Update a package policy by ID.', options: { tags: ['oas-tag:Fleet package policies'], }, @@ -259,7 +261,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { integrations: { writeIntegrationPolicies: true }, }, - description: 'Bulk delete package policies', + summary: 'Bulk delete package policies', options: { tags: ['oas-tag:Fleet package policies'], }, @@ -288,7 +290,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { integrations: { writeIntegrationPolicies: true }, }, - description: 'Delete package policy by ID', + summary: 'Delete a package policy', + description: 'Delete a package policy by ID.', options: { tags: ['oas-tag:Fleet package policies'], }, @@ -318,7 +321,8 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { integrations: { writeIntegrationPolicies: true }, }, - description: 'Upgrade package policy to a newer package version', + summary: 'Upgrade a package policy', + description: 'Upgrade a package policy to a newer package version.', options: { tags: ['oas-tag:Fleet package policies'], }, @@ -348,7 +352,7 @@ export const registerRoutes = (router: FleetAuthzRouter) => { fleetAuthz: { integrations: { readIntegrationPolicies: true }, }, - description: 'Dry run package policy upgrade', + summary: 'Dry run a package policy upgrade', options: { tags: ['oas-tag:Fleet package policies'], }, diff --git a/x-pack/plugins/fleet/server/routes/preconfiguration/index.ts b/x-pack/plugins/fleet/server/routes/preconfiguration/index.ts index e78396005d4c..c62c86953aca 100644 --- a/x-pack/plugins/fleet/server/routes/preconfiguration/index.ts +++ b/x-pack/plugins/fleet/server/routes/preconfiguration/index.ts @@ -18,14 +18,14 @@ export const registerRoutes = (router: FleetAuthzRouter) => { router.versioned .post({ path: PRECONFIGURATION_API_ROUTES.RESET_PATTERN, - access: 'internal', + access: 'public', fleetAuthz: { fleet: { all: true }, }, }) .addVersion( { - version: API_VERSIONS.internal.v1, + version: API_VERSIONS.public.v1, validate: false, }, @@ -34,14 +34,14 @@ export const registerRoutes = (router: FleetAuthzRouter) => { router.versioned .post({ path: PRECONFIGURATION_API_ROUTES.RESET_ONE_PATTERN, - access: 'internal', + access: 'public', fleetAuthz: { fleet: { all: true }, }, }) .addVersion( { - version: API_VERSIONS.internal.v1, + version: API_VERSIONS.public.v1, validate: { request: PostResetOnePreconfiguredAgentPoliciesSchema }, }, resetOnePreconfigurationHandler diff --git a/x-pack/plugins/fleet/server/routes/settings/index.ts b/x-pack/plugins/fleet/server/routes/settings/index.ts index b101937e45c2..04e6c2a95563 100644 --- a/x-pack/plugins/fleet/server/routes/settings/index.ts +++ b/x-pack/plugins/fleet/server/routes/settings/index.ts @@ -45,7 +45,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType authz.fleet.allAgentPolicies ); }, - description: `Get space settings`, + summary: `Get space settings`, }) .addVersion( { @@ -68,7 +68,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: { fleet: { allSettings: true }, }, - description: `Put space settings`, + summary: `Create space settings`, }) .addVersion( { @@ -92,7 +92,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: { fleet: { readSettings: true }, }, - description: `Get settings`, + summary: `Get settings`, options: { tags: ['oas-tag:Fleet internals'], }, @@ -123,7 +123,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: { fleet: { allSettings: true }, }, - description: `Update settings`, + summary: `Update settings`, options: { tags: ['oas-tag:Fleet internals'], }, @@ -154,7 +154,7 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: (authz) => { return authz.fleet.addAgents || authz.fleet.addFleetServers; }, - description: `Get enrollment settings`, + summary: `Get enrollment settings`, options: { tags: ['oas-tag:Fleet internals'], }, diff --git a/x-pack/plugins/fleet/server/routes/setup/index.ts b/x-pack/plugins/fleet/server/routes/setup/index.ts index 4b6fd2316832..2f41ff7eb687 100644 --- a/x-pack/plugins/fleet/server/routes/setup/index.ts +++ b/x-pack/plugins/fleet/server/routes/setup/index.ts @@ -42,7 +42,7 @@ export const registerFleetSetupRoute = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { setup: true }, }, - description: `Initiate Fleet setup`, + summary: `Initiate Fleet setup`, options: { tags: ['oas-tag:Fleet internals'], }, @@ -104,7 +104,7 @@ export const registerCreateFleetSetupRoute = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { setup: true }, }, - description: `Initiate agent setup`, + summary: `Initiate agent setup`, options: { tags: ['oas-tag:Elastic Agents'], }, @@ -135,7 +135,7 @@ export const registerGetFleetStatusRoute = (router: FleetAuthzRouter) => { fleetAuthz: { fleet: { setup: true }, }, - description: `Get agent setup info`, + summary: `Get agent setup info`, options: { tags: ['oas-tag:Elastic Agents'], }, diff --git a/x-pack/plugins/fleet/server/routes/uninstall_token/index.ts b/x-pack/plugins/fleet/server/routes/uninstall_token/index.ts index a90dd678e99d..3c5e25d414b2 100644 --- a/x-pack/plugins/fleet/server/routes/uninstall_token/index.ts +++ b/x-pack/plugins/fleet/server/routes/uninstall_token/index.ts @@ -31,7 +31,8 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: { fleet: { allAgents: true }, }, - description: 'List metadata for latest uninstall tokens per agent policy', + summary: 'Get metadata for latest uninstall tokens', + description: 'List the metadata for the latest uninstall tokens per agent policy.', options: { tags: ['oas-tag:Fleet uninstall tokens'], }, @@ -60,7 +61,8 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType fleetAuthz: { fleet: { allAgents: true }, }, - description: 'Get one decrypted uninstall token by its ID', + summary: 'Get a decrypted uninstall token', + description: 'Get one decrypted uninstall token by its ID.', options: { tags: ['oas-tag:Fleet uninstall tokens'], }, diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index ffb9381f8b30..706d0686b984 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -101,6 +101,7 @@ import { migratePackagePolicySetRequiresRootToV8150, } from './migrations/to_v8_15_0'; import { backfillAgentPolicyToV4 } from './model_versions/agent_policy_v4'; +import { backfillOutputPolicyToV7 } from './model_versions/outputs'; /* * Saved object types and mappings @@ -558,6 +559,18 @@ export const getSavedObjectTypes = ( }, ], }, + '7': { + changes: [ + { + type: 'mappings_deprecation', + deprecatedMappings: ['topics'], + }, + { + type: 'data_backfill', + backfillFn: backfillOutputPolicyToV7, + }, + ], + }, }, migrations: { '7.13.0': migrateOutputToV7130, diff --git a/x-pack/plugins/fleet/server/saved_objects/model_versions/outputs.ts b/x-pack/plugins/fleet/server/saved_objects/model_versions/outputs.ts new file mode 100644 index 000000000000..ed4e82d1c1ec --- /dev/null +++ b/x-pack/plugins/fleet/server/saved_objects/model_versions/outputs.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 { SavedObjectModelDataBackfillFn } from '@kbn/core-saved-objects-server'; + +import type { Output } from '../../../common'; + +export const backfillOutputPolicyToV7: SavedObjectModelDataBackfillFn< + Output & { + topics?: Array<{ + topic: string; + when?: { + type?: string; + condition?: string; + }; + }>; + }, + Output +> = (outputDoc) => { + if (outputDoc.attributes.type === 'kafka' && outputDoc.attributes.topics) { + if (!outputDoc.attributes.topic) { + outputDoc.attributes.topic = outputDoc.attributes.topics?.filter((t) => !t.when)?.[0]?.topic; + } + + delete outputDoc.attributes.topics; + } + return outputDoc; +}; diff --git a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts index 609c560906de..688320825326 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts @@ -1198,16 +1198,7 @@ ssl.test: 123 const policyOutput = transformOutputToFullPolicyOutput({ id: 'id123', hosts: ['test:9999'], - topics: [ - { - topic: 'test', - }, - // Deprecated conditionnal topic - { - topic: 'deprecated', - when: { condition: 'test:100', type: 'equals' }, - }, - ], + topic: 'test', is_default: false, is_default_monitoring: false, name: 'test output', diff --git a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts index 6a586364f31d..811685626515 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts @@ -386,15 +386,12 @@ export function transformOutputToFullPolicyOutput( round_robin, hash, topic, - topics, headers, timeout, broker_timeout, required_acks, } = output; - const kafkaTopic = topic ? topic : topics?.filter((t) => !t.when)?.[0]?.topic; - const transformPartition = () => { if (!partition) return {}; switch (partition) { @@ -431,7 +428,7 @@ export function transformOutputToFullPolicyOutput( ...(password ? { password } : {}), ...(sasl ? { sasl } : {}), partition: transformPartition(), - topic: kafkaTopic, + topic, headers: (headers ?? []).filter((item) => item.key !== '' || item.value !== ''), timeout, broker_timeout, diff --git a/x-pack/plugins/fleet/server/services/agent_policies/package_policies_to_agent_inputs.ts b/x-pack/plugins/fleet/server/services/agent_policies/package_policies_to_agent_inputs.ts index 807312fe5e7c..f2a39c6f8800 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/package_policies_to_agent_inputs.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/package_policies_to_agent_inputs.ts @@ -112,7 +112,8 @@ export const mergeInputsOverrides = ( export const getFullInputStreams = ( input: PackagePolicyInput, - allStreamEnabled: boolean = false + allStreamEnabled: boolean = false, + streamsOriginalIdsMap?: Map // Map of stream ids ): FullAgentPolicyInputStream => { return { ...(input.compiled_input || {}), @@ -121,8 +122,9 @@ export const getFullInputStreams = ( streams: input.streams .filter((stream) => stream.enabled || allStreamEnabled) .map((stream) => { + const streamId = stream.id; const fullStream: FullAgentPolicyInputStream = { - id: stream.id, + id: streamId, data_stream: stream.data_stream, ...stream.compiled_stream, ...Object.entries(stream.config || {}).reduce((acc, [key, { value }]) => { @@ -130,6 +132,8 @@ export const getFullInputStreams = ( return acc; }, {} as { [k: string]: any }), }; + streamsOriginalIdsMap?.set(fullStream.id, streamId); + return fullStream; }), } diff --git a/x-pack/plugins/fleet/server/services/agents/agentless_agent.test.ts b/x-pack/plugins/fleet/server/services/agents/agentless_agent.test.ts index fe8b7a220470..b278cda4fc27 100644 --- a/x-pack/plugins/fleet/server/services/agents/agentless_agent.test.ts +++ b/x-pack/plugins/fleet/server/services/agents/agentless_agent.test.ts @@ -814,9 +814,11 @@ describe('Agentless Agent service', () => { policy_id: 'mocked-agentless-agent-policy-id', stack_version: 'mocked-kibana-version-infinite', labels: { - organization: 'elastic', - division: 'cloud', - team: 'fleet', + owner: { + org: 'elastic', + division: 'cloud', + team: 'fleet', + }, }, }), headers: expect.anything(), @@ -911,9 +913,11 @@ describe('Agentless Agent service', () => { fleet_url: 'http://fleetserver:8220', policy_id: 'mocked-agentless-agent-policy-id', labels: { - organization: 'elastic', - division: 'cloud', - team: 'fleet', + owner: { + org: 'elastic', + division: 'cloud', + team: 'fleet', + }, }, }, headers: expect.anything(), diff --git a/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts index 7400b5958eb6..314af0ada7bf 100644 --- a/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts +++ b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts @@ -220,9 +220,11 @@ class AgentlessAgentService { agentlessAgentPolicy.global_data_tags?.find((tag) => tag.name === name)?.value; return { - organization: getGlobalTagValueByName(AGENTLESS_GLOBAL_TAG_NAME_ORGANIZATION), - division: getGlobalTagValueByName(AGENTLESS_GLOBAL_TAG_NAME_DIVISION), - team: getGlobalTagValueByName(AGENTLESS_GLOBAL_TAG_NAME_TEAM), + owner: { + org: getGlobalTagValueByName(AGENTLESS_GLOBAL_TAG_NAME_ORGANIZATION), + division: getGlobalTagValueByName(AGENTLESS_GLOBAL_TAG_NAME_DIVISION), + team: getGlobalTagValueByName(AGENTLESS_GLOBAL_TAG_NAME_TEAM), + }, }; } diff --git a/x-pack/plugins/fleet/server/services/app_context.ts b/x-pack/plugins/fleet/server/services/app_context.ts index 7dccb7ba1dfe..da40f8ff7d81 100644 --- a/x-pack/plugins/fleet/server/services/app_context.ts +++ b/x-pack/plugins/fleet/server/services/app_context.ts @@ -240,6 +240,7 @@ class AppContextService { // soClient as kibana internal users, be careful on how you use it, security is not enabled return appContextService.getSavedObjects().getScopedClient(fakeRequest, { excludedExtensions: [SECURITY_EXTENSION_ID, SPACES_EXTENSION_ID], + includedHiddenTypes: [UNINSTALL_TOKENS_SAVED_OBJECT_TYPE], }); } diff --git a/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts b/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts index 4bb6bad203e4..e2140947b9d6 100644 --- a/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts +++ b/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts @@ -13,15 +13,15 @@ metadata: name: elastic-agent namespace: kube-system labels: - app: elastic-agent + app.kubernetes.io/name: elastic-agent spec: selector: matchLabels: - app: elastic-agent + app.kubernetes.io/name: elastic-agent template: metadata: labels: - app: elastic-agent + app.kubernetes.io/name: elastic-agent spec: # Tolerations are needed to run Elastic Agent on Kubernetes control-plane nodes. # Agents running on control-plane nodes collect metrics from the control plane components (scheduler, controller manager) of Kubernetes @@ -41,13 +41,11 @@ spec: # args: # - -c # - >- - # mkdir -p /usr/share/elastic-agent/state/inputs.d && - # curl -sL https://github.com/elastic/elastic-agent/archive/9.0.tar.gz | tar xz -C /usr/share/elastic-agent/state/inputs.d --strip=5 "elastic-agent-9.0/deploy/kubernetes/elastic-agent-standalone/templates.d" - # securityContext: - # runAsUser: 0 + # mkdir -p /etc/elastic-agent/inputs.d && + # curl -sL https://github.com/elastic/elastic-agent/archive/9.0.tar.gz | tar xz -C /etc/elastic-agent/inputs.d --strip=5 "elastic-agent-9.0/deploy/kubernetes/elastic-agent-standalone/templates.d" # volumeMounts: - # - name: elastic-agent-state - # mountPath: /usr/share/elastic-agent/state + # - name: external-inputs + # mountPath: /etc/elastic-agent/inputs.d containers: - name: elastic-agent image: docker.elastic.co/beats/elastic-agent:VERSION @@ -76,14 +74,6 @@ spec: value: "false" securityContext: runAsUser: 0 - # The following capabilities are needed for 'Defend for containers' integration (cloud-defend) - # If you are using this integration, please uncomment these lines before applying. - #capabilities: - # add: - # - BPF # (since Linux 5.8) allows loading of BPF programs, create most map types, load BTF, iterate programs and maps. - # - PERFMON # (since Linux 5.8) allows attaching of BPF programs used for performance metrics and observability operations. - # - SYS_RESOURCE # Allow use of special resources or raising of resource limits. Used by 'Defend for Containers' to modify 'rlimit_memlock' - ######################################################################################## # The following capabilities are needed for Universal Profiling. # More fine graded capabilities are only available for newer Linux kernels. # If you are using the Universal Profiling integration, please uncomment these lines before applying. @@ -125,6 +115,9 @@ spec: mountPath: /sys/kernel/debug - name: elastic-agent-state mountPath: /usr/share/elastic-agent/state + # Uncomment if using hints feature + # - name: external-inputs + # mountPath: /usr/share/elastic-agent/state/inputs.d volumes: - name: datastreams configMap: @@ -151,8 +144,8 @@ spec: - name: var-lib hostPath: path: /var/lib - # Needed for 'Defend for containers' integration (cloud-defend) and Universal Profiling - # If you are not using one of these integrations, then these volumes and the corresponding + # Needed for Universal Profiling + # If you are not using this integration, then these volumes and the corresponding # mounts can be removed. - name: sys-kernel-debug hostPath: @@ -163,6 +156,9 @@ spec: hostPath: path: /var/lib/elastic-agent/kube-system/state type: DirectoryOrCreate + # Uncomment if using hints feature + # - name: external-inputs + # emptyDir: {} --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding @@ -210,7 +206,7 @@ kind: ClusterRole metadata: name: elastic-agent labels: - k8s-app: elastic-agent + app.kubernetes.io/name: elastic-agent rules: - apiGroups: [""] resources: @@ -282,7 +278,7 @@ metadata: # Should be the namespace where elastic-agent is running namespace: kube-system labels: - k8s-app: elastic-agent + app.kubernetes.io/name: elastic-agent rules: - apiGroups: - coordination.k8s.io @@ -296,7 +292,7 @@ metadata: name: elastic-agent-kubeadm-config namespace: kube-system labels: - k8s-app: elastic-agent + app.kubernetes.io/name: elastic-agent rules: - apiGroups: [""] resources: @@ -311,7 +307,7 @@ metadata: name: elastic-agent namespace: kube-system labels: - k8s-app: elastic-agent + app.kubernetes.io/name: elastic-agent --- `; @@ -323,15 +319,15 @@ metadata: name: elastic-agent namespace: kube-system labels: - app: elastic-agent + app.kubernetes.io/name: elastic-agent spec: selector: matchLabels: - app: elastic-agent + app.kubernetes.io/name: elastic-agent template: metadata: labels: - app: elastic-agent + app.kubernetes.io/name: elastic-agent spec: # Tolerations are needed to run Elastic Agent on Kubernetes control-plane nodes. # Agents running on control-plane nodes collect metrics from the control plane components (scheduler, controller manager) of Kubernetes @@ -383,14 +379,6 @@ spec: value: "false" securityContext: runAsUser: 0 - # The following capabilities are needed for 'Defend for containers' integration (cloud-defend) - # If you are using this integration, please uncomment these lines before applying. - #capabilities: - # add: - # - BPF # (since Linux 5.8) allows loading of BPF programs, create most map types, load BTF, iterate programs and maps. - # - PERFMON # (since Linux 5.8) allows attaching of BPF programs used for performance metrics and observability operations. - # - SYS_RESOURCE # Allow use of special resources or raising of resource limits. Used by 'Defend for Containers' to modify 'rlimit_memlock' - ######################################################################################## # The following capabilities are needed for Universal Profiling. # More fine graded capabilities are only available for newer Linux kernels. # If you are using the Universal Profiling integration, please uncomment these lines before applying. @@ -459,8 +447,8 @@ spec: hostPath: path: /etc/machine-id type: File - # Needed for 'Defend for containers' integration (cloud-defend) and Universal Profiling - # If you are not using one of these integrations, then these volumes and the corresponding + # Needed for Universal Profiling + # If you are not using this integration, then these volumes and the corresponding # mounts can be removed. - name: sys-kernel-debug hostPath: @@ -518,7 +506,7 @@ kind: ClusterRole metadata: name: elastic-agent labels: - k8s-app: elastic-agent + app.kubernetes.io/name: elastic-agent rules: - apiGroups: [""] resources: @@ -590,7 +578,7 @@ metadata: # Should be the namespace where elastic-agent is running namespace: kube-system labels: - k8s-app: elastic-agent + app.kubernetes.io/name: elastic-agent rules: - apiGroups: - coordination.k8s.io @@ -604,7 +592,7 @@ metadata: name: elastic-agent-kubeadm-config namespace: kube-system labels: - k8s-app: elastic-agent + app.kubernetes.io/name: elastic-agent rules: - apiGroups: [""] resources: @@ -619,6 +607,6 @@ metadata: name: elastic-agent namespace: kube-system labels: - k8s-app: elastic-agent + app.kubernetes.io/name: elastic-agent --- `; diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts index bf5684f29c20..6361aa1bf935 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts @@ -133,6 +133,20 @@ export async function installKibanaAssets(options: { return []; } + await createDefaultIndexPatterns(savedObjectsImporter); + await makeManagedIndexPatternsGlobal(savedObjectsClient); + + return await installKibanaSavedObjects({ + logger, + savedObjectsImporter, + kibanaAssets: assetsToInstall, + assetsChunkSize: MAX_ASSETS_TO_INSTALL_IN_PARALLEL, + }); +} + +export async function createDefaultIndexPatterns( + savedObjectsImporter: SavedObjectsImporterContract +) { // Create index patterns separately with `overwrite: false` to prevent blowing away users' runtime fields. // These don't get retried on conflict, because we expect that they exist once an integration has been installed. const indexPatternSavedObjects = getIndexPatternSavedObjects() as ArchiveAsset[]; @@ -143,15 +157,6 @@ export async function installKibanaAssets(options: { refresh: false, managed: true, }); - - await makeManagedIndexPatternsGlobal(savedObjectsClient); - - return await installKibanaSavedObjects({ - logger, - savedObjectsImporter, - kibanaAssets: assetsToInstall, - assetsChunkSize: MAX_ASSETS_TO_INSTALL_IN_PARALLEL, - }); } export async function installKibanaAssetsAndReferencesMultispace({ diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install_with_streaming.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install_with_streaming.ts index fca6cf27a0cd..45c4aee73b58 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install_with_streaming.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install_with_streaming.ts @@ -5,17 +5,20 @@ * 2.0. */ -import type { SavedObject, SavedObjectsClientContract } from '@kbn/core/server'; +import type { SavedObjectsClientContract } from '@kbn/core/server'; -import type { Installation, PackageInstallContext } from '../../../../../common/types'; +import type { PackageInstallContext } from '../../../../../common/types'; import type { KibanaAssetReference, KibanaAssetType } from '../../../../types'; import { getPathParts } from '../../archive'; import { saveKibanaAssetsRefs } from '../../packages/install'; +import { makeManagedIndexPatternsGlobal } from '../index_pattern/install'; + import type { ArchiveAsset } from './install'; import { KibanaSavedObjectTypeMapping, + createDefaultIndexPatterns, createSavedObjectKibanaAsset, isKibanaAssetType, toAssetReference, @@ -27,7 +30,6 @@ interface InstallKibanaAssetsWithStreamingArgs { packageInstallContext: PackageInstallContext; spaceId: string; savedObjectsClient: SavedObjectsClientContract; - installedPkg?: SavedObject | undefined; } const MAX_ASSETS_TO_INSTALL_IN_PARALLEL = 100; @@ -37,11 +39,14 @@ export async function installKibanaAssetsWithStreaming({ packageInstallContext, savedObjectsClient, pkgName, - installedPkg, }: InstallKibanaAssetsWithStreamingArgs): Promise { const { archiveIterator } = packageInstallContext; - const { savedObjectClientWithSpace } = getSpaceAwareSaveobjectsClients(spaceId); + const { savedObjectClientWithSpace, savedObjectsImporter } = + getSpaceAwareSaveobjectsClients(spaceId); + + await createDefaultIndexPatterns(savedObjectsImporter); + await makeManagedIndexPatternsGlobal(savedObjectsClient); const assetRefs: KibanaAssetReference[] = []; let batch: ArchiveAsset[] = []; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/__fixtures__/docker_2_11_0.ts b/x-pack/plugins/fleet/server/services/epm/packages/__fixtures__/docker_2_11_0.ts new file mode 100644 index 000000000000..67bde1882cfe --- /dev/null +++ b/x-pack/plugins/fleet/server/services/epm/packages/__fixtures__/docker_2_11_0.ts @@ -0,0 +1,230 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const DOCKER_2_11_0_PACKAGE_INFO = { + name: 'docker', + title: 'Docker', + version: '2.11.0', + release: 'ga', + description: 'Collect metrics and logs from Docker instances with Elastic Agent.', + type: 'integration', + download: '/epr/docker/docker-2.11.0.zip', + path: '/package/docker/2.11.0', + icons: [ + { + src: '/img/logo_docker.svg', + path: '/package/docker/2.11.0/img/logo_docker.svg', + title: 'logo docker', + size: '32x32', + type: 'image/svg+xml', + }, + ], + conditions: { + kibana: { + version: '^8.8.0', + }, + }, + owner: { + type: 'elastic', + github: 'elastic/obs-cloudnative-monitoring', + }, + categories: ['observability', 'containers'], + signature_path: '/epr/docker/docker-2.11.0.zip.sig', + format_version: '3.2.2', + readme: '/package/docker/2.11.0/docs/README.md', + license: 'basic', + screenshots: [ + { + src: '/img/docker-overview.png', + path: '/package/docker/2.11.0/img/docker-overview.png', + title: 'Docker Overview', + size: '5120x2562', + type: 'image/png', + }, + ], + assets: [ + '/package/docker/2.11.0/LICENSE.txt', + '/package/docker/2.11.0/changelog.yml', + '/package/docker/2.11.0/manifest.yml', + '/package/docker/2.11.0/docs/README.md', + '/package/docker/2.11.0/img/docker-overview.png', + '/package/docker/2.11.0/img/logo_docker.svg', + '/package/docker/2.11.0/data_stream/container/manifest.yml', + '/package/docker/2.11.0/data_stream/container/sample_event.json', + '/package/docker/2.11.0/data_stream/container_logs/manifest.yml', + '/package/docker/2.11.0/data_stream/container_logs/sample_event.json', + '/package/docker/2.11.0/data_stream/cpu/manifest.yml', + '/package/docker/2.11.0/data_stream/cpu/sample_event.json', + '/package/docker/2.11.0/data_stream/diskio/manifest.yml', + '/package/docker/2.11.0/data_stream/diskio/sample_event.json', + '/package/docker/2.11.0/data_stream/event/manifest.yml', + '/package/docker/2.11.0/data_stream/event/sample_event.json', + '/package/docker/2.11.0/data_stream/healthcheck/manifest.yml', + '/package/docker/2.11.0/data_stream/healthcheck/sample_event.json', + '/package/docker/2.11.0/data_stream/image/manifest.yml', + '/package/docker/2.11.0/data_stream/image/sample_event.json', + '/package/docker/2.11.0/data_stream/info/manifest.yml', + '/package/docker/2.11.0/data_stream/info/sample_event.json', + '/package/docker/2.11.0/data_stream/memory/manifest.yml', + '/package/docker/2.11.0/data_stream/memory/sample_event.json', + '/package/docker/2.11.0/data_stream/network/manifest.yml', + '/package/docker/2.11.0/data_stream/network/sample_event.json', + '/package/docker/2.11.0/kibana/dashboard/docker-AV4REOpp5NkDleZmzKkE.json', + '/package/docker/2.11.0/kibana/search/docker-Metrics-Docker.json', + '/package/docker/2.11.0/data_stream/container/fields/base-fields.yml', + '/package/docker/2.11.0/data_stream/container/fields/ecs.yml', + '/package/docker/2.11.0/data_stream/container/fields/fields.yml', + '/package/docker/2.11.0/data_stream/container_logs/fields/agent.yml', + '/package/docker/2.11.0/data_stream/container_logs/fields/base-fields.yml', + '/package/docker/2.11.0/data_stream/container_logs/fields/ecs.yml', + '/package/docker/2.11.0/data_stream/container_logs/fields/fields.yml', + '/package/docker/2.11.0/data_stream/cpu/fields/base-fields.yml', + '/package/docker/2.11.0/data_stream/cpu/fields/ecs.yml', + '/package/docker/2.11.0/data_stream/cpu/fields/fields.yml', + '/package/docker/2.11.0/data_stream/diskio/fields/base-fields.yml', + '/package/docker/2.11.0/data_stream/diskio/fields/ecs.yml', + '/package/docker/2.11.0/data_stream/diskio/fields/fields.yml', + '/package/docker/2.11.0/data_stream/event/fields/base-fields.yml', + '/package/docker/2.11.0/data_stream/event/fields/ecs.yml', + '/package/docker/2.11.0/data_stream/event/fields/fields.yml', + '/package/docker/2.11.0/data_stream/healthcheck/fields/base-fields.yml', + '/package/docker/2.11.0/data_stream/healthcheck/fields/ecs.yml', + '/package/docker/2.11.0/data_stream/healthcheck/fields/fields.yml', + '/package/docker/2.11.0/data_stream/image/fields/base-fields.yml', + '/package/docker/2.11.0/data_stream/image/fields/ecs.yml', + '/package/docker/2.11.0/data_stream/image/fields/fields.yml', + '/package/docker/2.11.0/data_stream/info/fields/base-fields.yml', + '/package/docker/2.11.0/data_stream/info/fields/ecs.yml', + '/package/docker/2.11.0/data_stream/info/fields/fields.yml', + '/package/docker/2.11.0/data_stream/memory/fields/base-fields.yml', + '/package/docker/2.11.0/data_stream/memory/fields/ecs.yml', + '/package/docker/2.11.0/data_stream/memory/fields/fields.yml', + '/package/docker/2.11.0/data_stream/network/fields/base-fields.yml', + '/package/docker/2.11.0/data_stream/network/fields/ecs.yml', + '/package/docker/2.11.0/data_stream/network/fields/fields.yml', + '/package/docker/2.11.0/data_stream/container/agent/stream/stream.yml.hbs', + '/package/docker/2.11.0/data_stream/container_logs/agent/stream/stream.yml.hbs', + '/package/docker/2.11.0/data_stream/cpu/agent/stream/stream.yml.hbs', + '/package/docker/2.11.0/data_stream/diskio/agent/stream/stream.yml.hbs', + '/package/docker/2.11.0/data_stream/event/agent/stream/stream.yml.hbs', + '/package/docker/2.11.0/data_stream/healthcheck/agent/stream/stream.yml.hbs', + '/package/docker/2.11.0/data_stream/image/agent/stream/stream.yml.hbs', + '/package/docker/2.11.0/data_stream/info/agent/stream/stream.yml.hbs', + '/package/docker/2.11.0/data_stream/memory/agent/stream/stream.yml.hbs', + '/package/docker/2.11.0/data_stream/network/agent/stream/stream.yml.hbs', + ], + policy_templates: [ + { + name: 'docker', + title: 'Docker logs and metrics', + description: 'Collect logs and metrics from Docker instances', + inputs: [ + { + type: 'filestream', + title: 'Collect Docker container logs', + description: 'Collecting docker container logs', + }, + ], + multiple: true, + }, + ], + data_streams: [ + { + type: 'logs', + dataset: 'docker.container_logs', + title: 'Docker container logs', + release: 'ga', + streams: [ + { + input: 'filestream', + vars: [ + { + name: 'paths', + type: 'text', + title: 'Docker container log path', + multi: true, + required: true, + show_user: false, + default: ['/var/lib/docker/containers/${docker.container.id}/*-json.log'], + }, + { + name: 'containerParserStream', + type: 'text', + title: "Container parser's stream configuration", + multi: false, + required: true, + show_user: false, + default: 'all', + }, + { + name: 'condition', + type: 'text', + title: 'Condition', + description: + 'Condition to filter when to apply this datastream. Refer to [Docker provider](https://www.elastic.co/guide/en/fleet/current/docker-provider.html) to find the available keys and to [Conditions](https://www.elastic.co/guide/en/fleet/current/dynamic-input-configuration.html#conditions) on how to use the available keys in conditions.', + multi: false, + required: false, + show_user: true, + }, + { + name: 'additionalParsersConfig', + type: 'yaml', + title: 'Additional parsers configuration', + multi: false, + required: true, + show_user: false, + default: + "# - ndjson:\n# target: json\n# ignore_decoding_error: true\n# - multiline:\n# type: pattern\n# pattern: '^\\['\n# negate: true\n# match: after\n", + }, + { + name: 'processors', + type: 'yaml', + title: 'Processors', + description: + 'Processors are used to reduce the number of fields in the exported event or to enhance the event with metadata. This executes in the agent before the events are shipped. See [Processors](https://www.elastic.co/guide/en/beats/filebeat/current/filtering-and-enhancing-data.html) for details.', + multi: false, + required: false, + show_user: false, + }, + ], + template_path: 'stream.yml.hbs', + title: 'Collect Docker container logs', + description: 'Collect Docker container logs', + enabled: true, + }, + ], + package: 'docker', + elasticsearch: {}, + path: 'container_logs', + }, + ], +}; + +export const DOCKER_2_11_0_ASSETS_MAP = new Map([ + [ + 'docker-2.11.0/data_stream/container_logs/agent/stream/stream.yml.hbs', + Buffer.from(`id: docker-container-logs-\${docker.container.name}-\${docker.container.id} +paths: +{{#each paths}} + - {{this}} +{{/each}} +{{#if condition}} +condition: {{ condition }} +{{/if}} +parsers: +- container: + stream: {{ containerParserStream }} + format: docker +{{ additionalParsersConfig }} + +{{#if processors}} +processors: +{{processors}} +{{/if}} +`), + ], +]); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/__fixtures__/redis_1_18_0_package_info.json b/x-pack/plugins/fleet/server/services/epm/packages/__fixtures__/redis_1_18_0_package_info.json index 57c9b0c68fac..5aa5c4a878ba 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/__fixtures__/redis_1_18_0_package_info.json +++ b/x-pack/plugins/fleet/server/services/epm/packages/__fixtures__/redis_1_18_0_package_info.json @@ -139,6 +139,15 @@ "show_user": false, "default": "20s" }, + { + "name": "tags", + "type": "text", + "title": "Tags", + "multi": true, + "required": false, + "show_user": false, + "default": "" + }, { "name": "maxconn", "type": "integer", @@ -203,6 +212,15 @@ { "input": "redis/metrics", "vars": [ + { + "name": "tags_streams", + "type": "text", + "title": "Tags in streams", + "multi": true, + "required": false, + "show_user": false, + "default": "" + }, { "name": "key.patterns", "type": "yaml", diff --git a/x-pack/plugins/fleet/server/services/epm/packages/__fixtures__/redis_1_18_0_streams_template.ts b/x-pack/plugins/fleet/server/services/epm/packages/__fixtures__/redis_1_18_0_streams_template.ts index 5ff46f358bbe..207a48d7132a 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/__fixtures__/redis_1_18_0_streams_template.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/__fixtures__/redis_1_18_0_streams_template.ts @@ -76,6 +76,15 @@ period: {{period}} processors: {{processors}} {{/if}} +tags: + - test +{{#each tags as |tag i|}} + - {{tag}} +{{/each}} +tags_streams: +{{#each tags_streams as |tag i|}} + - {{tag}} +{{/each}} `), ], ]); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/__snapshots__/get_templates_inputs.test.ts.snap b/x-pack/plugins/fleet/server/services/epm/packages/__snapshots__/get_templates_inputs.test.ts.snap index b3a428c0e5a5..56e4f7ee0931 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/__snapshots__/get_templates_inputs.test.ts.snap +++ b/x-pack/plugins/fleet/server/services/epm/packages/__snapshots__/get_templates_inputs.test.ts.snap @@ -8,17 +8,16 @@ exports[`Fleet - getTemplateInputs should work for input package 1`] = ` streams: # Custom log file: Custom log file - id: logfile-log.logs - data_stream: - dataset: - # Dataset name: Set the name for your dataset. Changing the dataset will send the data to a different index. You can't use \`-\` in the name of a dataset and only valid characters for [Elasticsearch index names](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html). - - paths: - - # Log file path: Path to log files to be collected - exclude_files: - - # Exclude files: Patterns to be ignored ignore_older: 72h - tags: - - # Tags: Tags to include in the published event + # data_stream: + # dataset: + # # Dataset name: Set the name for your dataset. Changing the dataset will send the data to a different index. You can't use \`-\` in the name of a dataset and only valid characters for [Elasticsearch index names](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html). + # paths: + # - # Log file path: Path to log files to be collected + # exclude_files: + # - # Exclude files: Patterns to be ignored + # tags: + # - # Tags: Tags to include in the published event " `; @@ -49,8 +48,34 @@ exports[`Fleet - getTemplateInputs should work for integration package 1`] = ` pattern: '*' maxconn: 10 network: tcp - username: # Username - password: # Password period: 10s + tags: + - test + # - # Tags + # username: # Username + # password: # Password + # tags_streams: + # - # Tags in streams +" +`; + +exports[`Fleet - getTemplateInputs should work for package with dynamic ids 1`] = ` +"inputs: + # Collect Docker container logs: Collecting docker container logs + - id: docker-filestream + type: filestream + streams: + # Collect Docker container logs: Collect Docker container logs + - id: docker-container-logs-\${docker.container.name}-\${docker.container.id} + data_stream: + dataset: docker.container_logs + type: logs + paths: + - /var/lib/docker/containers/\${docker.container.id}/*-json.log + parsers: + - container: + stream: all + format: docker + # condition: # Condition: Condition to filter when to apply this datastream. Refer to [Docker provider](https://www.elastic.co/guide/en/fleet/current/docker-provider.html) to find the available keys and to [Conditions](https://www.elastic.co/guide/en/fleet/current/dynamic-input-configuration.html#conditions) on how to use the available keys in conditions. " `; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get_template_inputs.ts b/x-pack/plugins/fleet/server/services/epm/packages/get_template_inputs.ts index 8c63f4b093dd..f76b739904f3 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/get_template_inputs.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/get_template_inputs.ts @@ -51,20 +51,31 @@ type PackageWithInputAndStreamIndexed = Record< // Function based off storedPackagePolicyToAgentInputs, it only creates the `streams` section instead of the FullAgentPolicyInput export const templatePackagePolicyToFullInputStreams = ( - packagePolicyInputs: PackagePolicyInput[] + packagePolicyInputs: PackagePolicyInput[], + inputAndStreamsIdsMap?: Map }> ): TemplateAgentPolicyInput[] => { const fullInputsStreams: TemplateAgentPolicyInput[] = []; if (!packagePolicyInputs || packagePolicyInputs.length === 0) return fullInputsStreams; packagePolicyInputs.forEach((input) => { + const streamsIdsMap = new Map(); + + const inputId = input.policy_template + ? `${input.policy_template}-${input.type}` + : `${input.type}`; const fullInputStream = { // @ts-ignore-next-line the following id is actually one level above the one in fullInputStream, but the linter thinks it gets overwritten - id: input.policy_template ? `${input.policy_template}-${input.type}` : `${input.type}`, + id: inputId, type: input.type, - ...getFullInputStreams(input, true), + ...getFullInputStreams(input, true, streamsIdsMap), }; + inputAndStreamsIdsMap?.set(fullInputStream.id, { + originalId: inputId, + streams: streamsIdsMap, + }); + // deeply merge the input.config values with the full policy input stream merge( fullInputStream, @@ -167,8 +178,13 @@ export async function getTemplateInputs( ...emptyPackagePolicy, inputs: compiledInputs, }; + const inputIdsDestinationMap = new Map< + string, + { originalId: string; streams: Map } + >(); const inputs = templatePackagePolicyToFullInputStreams( - packagePolicyWithInputs.inputs as PackagePolicyInput[] + packagePolicyWithInputs.inputs as PackagePolicyInput[], + inputIdsDestinationMap ); if (format === 'json') { @@ -181,7 +197,7 @@ export async function getTemplateInputs( sortKeys: _sortYamlKeys, } ); - return addCommentsToYaml(yaml, buildIndexedPackage(packageInfo)); + return addCommentsToYaml(yaml, buildIndexedPackage(packageInfo), inputIdsDestinationMap); } return { inputs: [] }; @@ -247,7 +263,8 @@ function buildIndexedPackage(packageInfo: PackageInfo): PackageWithInputAndStrea function addCommentsToYaml( yaml: string, - packageIndexInputAndStreams: PackageWithInputAndStreamIndexed + packageIndexInputAndStreams: PackageWithInputAndStreamIndexed, + inputIdsDestinationMap: Map }> ) { const doc = yamlDoc.parseDocument(yaml); // Add input and streams comments @@ -261,28 +278,16 @@ function addCommentsToYaml( if (!yamlDoc.isScalar(inputIdNode)) { return; } - const inputId = inputIdNode.value as string; + const inputId = + inputIdsDestinationMap.get(inputIdNode.value as string)?.originalId ?? + (inputIdNode.value as string); const pkgInput = packageIndexInputAndStreams[inputId]; if (pkgInput) { inputItem.commentBefore = ` ${pkgInput.title}${ pkgInput.description ? `: ${pkgInput.description}` : '' }`; - yamlDoc.visit(inputItem, { - Scalar(key, node) { - if (node.value) { - const val = node.value.toString(); - for (const varDef of pkgInput.vars ?? []) { - const placeholder = getPlaceholder(varDef); - if (val.includes(placeholder)) { - node.comment = ` ${varDef.title}${ - varDef.description ? `: ${varDef.description}` : '' - }`; - } - } - } - }, - }); + commentVariablesInYaml(inputItem, pkgInput.vars ?? []); const yamlStreams = inputItem.get('streams'); if (!yamlDoc.isCollection(yamlStreams)) { @@ -294,27 +299,16 @@ function addCommentsToYaml( } const streamIdNode = streamItem.get('id', true); if (yamlDoc.isScalar(streamIdNode)) { - const streamId = streamIdNode.value as string; + const streamId = + inputIdsDestinationMap + .get(inputIdNode.value as string) + ?.streams?.get(streamIdNode.value as string) ?? (streamIdNode.value as string); const pkgStream = pkgInput.streams[streamId]; if (pkgStream) { streamItem.commentBefore = ` ${pkgStream.title}${ pkgStream.description ? `: ${pkgStream.description}` : '' }`; - yamlDoc.visit(streamItem, { - Scalar(key, node) { - if (node.value) { - const val = node.value.toString(); - for (const varDef of pkgStream.vars ?? []) { - const placeholder = getPlaceholder(varDef); - if (val.includes(placeholder)) { - node.comment = ` ${varDef.title}${ - varDef.description ? `: ${varDef.description}` : '' - }`; - } - } - } - }, - }); + commentVariablesInYaml(streamItem, pkgStream.vars ?? []); } } }); @@ -324,3 +318,71 @@ function addCommentsToYaml( return doc.toString(); } + +function commentVariablesInYaml(rootNode: yamlDoc.Node, vars: RegistryVarsEntry[] = []) { + // Node need to be deleted after the end of the visit to be able to visit every node + const toDeleteFn: Array<() => void> = []; + yamlDoc.visit(rootNode, { + Scalar(key, node, path) { + if (node.value) { + const val = node.value.toString(); + for (const varDef of vars) { + const placeholder = getPlaceholder(varDef); + if (val.includes(placeholder)) { + node.comment = ` ${varDef.title}${varDef.description ? `: ${varDef.description}` : ''}`; + + const paths = [...path].reverse(); + + let prevPart: yamlDoc.Node | yamlDoc.Document | yamlDoc.Pair = node; + + for (const pathPart of paths) { + if (yamlDoc.isCollection(pathPart)) { + // If only one items in the collection comment the whole collection + if (pathPart.items.length === 1) { + continue; + } + } + if (yamlDoc.isSeq(pathPart)) { + const commentDoc = new yamlDoc.Document(new yamlDoc.YAMLSeq()); + commentDoc.add(prevPart); + const commentStr = commentDoc.toString().trimEnd(); + pathPart.comment = pathPart.comment + ? `${pathPart.comment} ${commentStr}` + : ` ${commentStr}`; + const keyToDelete = prevPart; + + toDeleteFn.push(() => { + pathPart.items.forEach((item, index) => { + if (item === keyToDelete) { + pathPart.delete(new yamlDoc.Scalar(index)); + } + }); + }); + return; + } + + if (yamlDoc.isMap(pathPart)) { + if (yamlDoc.isPair(prevPart)) { + const commentDoc = new yamlDoc.Document(new yamlDoc.YAMLMap()); + commentDoc.add(prevPart); + const commentStr = commentDoc.toString().trimEnd(); + + pathPart.comment = pathPart.comment + ? `${pathPart.comment}\n ${commentStr.toString()}` + : ` ${commentStr.toString()}`; + const keyToDelete = prevPart.key; + toDeleteFn.push(() => pathPart.delete(keyToDelete)); + } + return; + } + + prevPart = pathPart; + } + } + } + } + }, + }); + + toDeleteFn.forEach((deleteFn) => deleteFn()); +} diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get_templates_inputs.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/get_templates_inputs.test.ts index 087002f21285..1a3738d8eaa8 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/get_templates_inputs.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/get_templates_inputs.test.ts @@ -16,6 +16,7 @@ import REDIS_1_18_0_PACKAGE_INFO from './__fixtures__/redis_1_18_0_package_info. import { getPackageAssetsMap, getPackageInfo } from './get'; import { REDIS_ASSETS_MAP } from './__fixtures__/redis_1_18_0_streams_template'; import { LOGS_2_3_0_ASSETS_MAP, LOGS_2_3_0_PACKAGE_INFO } from './__fixtures__/logs_2_3_0'; +import { DOCKER_2_11_0_PACKAGE_INFO, DOCKER_2_11_0_ASSETS_MAP } from './__fixtures__/docker_2_11_0'; jest.mock('./get'); @@ -41,6 +42,7 @@ packageInfoCache.set('limited_package-0.0.0', { packageInfoCache.set('redis-1.18.0', REDIS_1_18_0_PACKAGE_INFO); packageInfoCache.set('log-2.3.0', LOGS_2_3_0_PACKAGE_INFO); +packageInfoCache.set('docker-2.11.0', DOCKER_2_11_0_PACKAGE_INFO); describe('Fleet - templatePackagePolicyToFullInputStreams', () => { const mockInput: PackagePolicyInput = { @@ -330,6 +332,9 @@ describe('Fleet - getTemplateInputs', () => { if (packageInfo.name === 'log') { return LOGS_2_3_0_ASSETS_MAP; } + if (packageInfo.name === 'docker') { + return DOCKER_2_11_0_ASSETS_MAP; + } return new Map(); }); @@ -350,6 +355,14 @@ describe('Fleet - getTemplateInputs', () => { expect(template).toMatchSnapshot(); }); + it('should work for package with dynamic ids', async () => { + const soMock = savedObjectsClientMock.create(); + soMock.get.mockResolvedValue({ attributes: {} } as any); + const template = await getTemplateInputs(soMock, 'docker', '2.11.0', 'yml'); + + expect(template).toMatchSnapshot(); + }); + it('should work for input package', async () => { const soMock = savedObjectsClientMock.create(); soMock.get.mockResolvedValue({ attributes: {} } as any); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_install_kibana_assets.ts b/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_install_kibana_assets.ts index aabd23f2eb9c..22c785f56840 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_install_kibana_assets.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/steps/step_install_kibana_assets.ts @@ -40,7 +40,7 @@ export async function stepInstallKibanaAssets(context: InstallContext) { } export async function stepInstallKibanaAssetsWithStreaming(context: InstallContext) { - const { savedObjectsClient, installedPkg, packageInstallContext, spaceId } = context; + const { savedObjectsClient, packageInstallContext, spaceId } = context; const { packageInfo } = packageInstallContext; const { name: pkgName } = packageInfo; @@ -51,7 +51,6 @@ export async function stepInstallKibanaAssetsWithStreaming(context: InstallConte savedObjectsClient, pkgName, packageInstallContext, - installedPkg, spaceId, }) ); diff --git a/x-pack/plugins/fleet/server/services/output.test.ts b/x-pack/plugins/fleet/server/services/output.test.ts index d35701e77f88..f2dab8401e64 100644 --- a/x-pack/plugins/fleet/server/services/output.test.ts +++ b/x-pack/plugins/fleet/server/services/output.test.ts @@ -824,7 +824,7 @@ describe('Output Service', () => { is_default_monitoring: false, name: 'Test', type: 'kafka', - topics: [{ topic: 'test' }], + topic: 'test', }, { id: 'output-test' } ) @@ -1206,7 +1206,6 @@ describe('Output Service', () => { ssl: null, timeout: null, topic: null, - topics: null, headers: null, username: null, version: null, @@ -1330,7 +1329,6 @@ describe('Output Service', () => { sasl: null, timeout: null, topic: null, - topics: null, headers: null, username: null, version: null, diff --git a/x-pack/plugins/fleet/server/services/output.ts b/x-pack/plugins/fleet/server/services/output.ts index b5041d9f1df3..ceecd29562fc 100644 --- a/x-pack/plugins/fleet/server/services/output.ts +++ b/x-pack/plugins/fleet/server/services/output.ts @@ -919,7 +919,6 @@ class OutputService { target.random = null; target.round_robin = null; target.hash = null; - target.topics = null; target.topic = null; target.headers = null; target.timeout = null; diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts index 68b4cf2457e2..9d71e1595848 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts @@ -318,7 +318,6 @@ async function isPreconfiguredOutputDifferentFromCurrent( isDifferent(existingOutput.round_robin, preconfiguredOutput.round_robin) || isDifferent(existingOutput.hash, preconfiguredOutput.hash) || isDifferent(existingOutput.topic, preconfiguredOutput.topic) || - isDifferent(existingOutput.topics, preconfiguredOutput.topics) || isDifferent(existingOutput.headers, preconfiguredOutput.headers) || isDifferent(existingOutput.timeout, preconfiguredOutput.timeout) || isDifferent(existingOutput.broker_timeout, preconfiguredOutput.broker_timeout) || diff --git a/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts b/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts index 0a44a3df0f29..1f58fcafd396 100644 --- a/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts +++ b/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts @@ -46,7 +46,7 @@ import { appContextService } from '../../app_context'; import { agentPolicyService, getAgentPolicySavedObjectType } from '../../agent_policy'; import { isSpaceAwarenessEnabled } from '../../spaces/helpers'; -interface UninstallTokenSOAttributes { +export interface UninstallTokenSOAttributes { policy_id: string; token: string; token_plain: string; diff --git a/x-pack/plugins/fleet/server/services/spaces/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/spaces/agent_policy.test.ts index ab69d4708c43..079148a6ae04 100644 --- a/x-pack/plugins/fleet/server/services/spaces/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/spaces/agent_policy.test.ts @@ -39,6 +39,22 @@ describe('updateAgentPolicySpaces', () => { jest .mocked(appContextService.getInternalUserSOClientWithoutSpaceExtension()) .updateObjectsSpaces.mockResolvedValue({ objects: [] }); + + jest + .mocked(appContextService.getInternalUserSOClientWithoutSpaceExtension()) + .find.mockResolvedValue({ + total: 1, + page: 1, + per_page: 100, + saved_objects: [ + { + id: 'token1', + attributes: { + namespaces: ['default'], + }, + } as any, + ], + }); }); it('does nothings if agent policy already in correct space', async () => { @@ -87,6 +103,18 @@ describe('updateAgentPolicySpaces', () => { ['default'], { namespace: 'default', refresh: 'wait_for' } ); + + expect( + jest.mocked(appContextService.getInternalUserSOClientWithoutSpaceExtension()).bulkUpdate + ).toBeCalledWith([ + { + id: 'token1', + type: 'fleet-uninstall-tokens', + attributes: { + namespaces: ['test'], + }, + }, + ]); }); it('throw when trying to change space to a policy with reusable package policies', async () => { 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 2f8d5ff1b14c..e123ca442665 100644 --- a/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts @@ -13,6 +13,8 @@ import { AGENTS_INDEX, AGENT_POLICY_SAVED_OBJECT_TYPE, PACKAGE_POLICY_SAVED_OBJECT_TYPE, + SO_SEARCH_LIMIT, + UNINSTALL_TOKENS_SAVED_OBJECT_TYPE, } from '../../../common/constants'; import { appContextService } from '../app_context'; @@ -22,6 +24,7 @@ import { packagePolicyService } from '../package_policy'; import { FleetError, HostedAgentPolicyRestrictionRelatedError } from '../../errors'; import { isSpaceAwarenessEnabled } from './helpers'; +import type { UninstallTokenSOAttributes } from '../security/uninstall_token_service'; export async function updateAgentPolicySpaces({ agentPolicyId, @@ -112,6 +115,25 @@ export async function updateAgentPolicySpaces({ } } + // Update uninstall tokens + const uninstallTokensRes = await soClient.find({ + perPage: SO_SEARCH_LIMIT, + type: UNINSTALL_TOKENS_SAVED_OBJECT_TYPE, + filter: `${UNINSTALL_TOKENS_SAVED_OBJECT_TYPE}.attributes.policy_id:"${agentPolicyId}"`, + }); + + if (uninstallTokensRes.total > 0) { + await soClient.bulkUpdate( + uninstallTokensRes.saved_objects.map((so) => ({ + id: so.id, + type: UNINSTALL_TOKENS_SAVED_OBJECT_TYPE, + attributes: { + namespaces: newSpaceIds, + }, + })) + ); + } + // Update fleet server index agents, enrollment api keys await esClient.updateByQuery({ index: ENROLLMENT_API_KEYS_INDEX, diff --git a/x-pack/plugins/fleet/server/types/models/output.ts b/x-pack/plugins/fleet/server/types/models/output.ts index 4385f9911e3d..2f02819554d5 100644 --- a/x-pack/plugins/fleet/server/types/models/output.ts +++ b/x-pack/plugins/fleet/server/types/models/output.ts @@ -13,7 +13,6 @@ import { kafkaConnectionType, kafkaPartitionType, kafkaSaslMechanism, - kafkaTopicWhenType, kafkaVerificationModes, outputType, } from '../../../common/constants'; @@ -196,29 +195,6 @@ const LogstashUpdateSchema = { ), }; -/** - * Kafka schemas - */ - -const KafkaTopicsSchema = schema.arrayOf( - schema.object({ - topic: schema.string(), - when: schema.maybe( - schema.object({ - type: schema.maybe( - schema.oneOf([ - schema.literal(kafkaTopicWhenType.Equals), - schema.literal(kafkaTopicWhenType.Contains), - schema.literal(kafkaTopicWhenType.Regexp), - ]) - ), - condition: schema.maybe(schema.string()), - }) - ), - }), - { minSize: 1 } -); - export const KafkaSchema = { ...BaseSchema, type: schema.literal(outputType.Kafka), @@ -303,7 +279,6 @@ export const KafkaSchema = { schema.object({ hash: schema.maybe(schema.string()), random: schema.maybe(schema.boolean()) }) ), topic: schema.maybe(schema.string()), - topics: schema.maybe(KafkaTopicsSchema), headers: schema.maybe( schema.arrayOf(schema.object({ key: schema.string(), value: schema.string() })) ), @@ -335,7 +310,6 @@ const KafkaUpdateSchema = { schema.literal(kafkaAuthType.Kerberos), ]) ), - topics: schema.maybe(KafkaTopicsSchema), }; export const OutputSchema = schema.oneOf([ diff --git a/x-pack/plugins/fleet/server/types/models/preconfiguration.test.ts b/x-pack/plugins/fleet/server/types/models/preconfiguration.test.ts index a436f799fc17..a924ba7c8c7d 100644 --- a/x-pack/plugins/fleet/server/types/models/preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/types/models/preconfiguration.test.ts @@ -119,7 +119,7 @@ describe('Test preconfiguration schema', () => { type: 'kafka', hosts: ['localhost:9200'], auth_type: 'ssl', - topics: [{ topic: 'topic1' }], + topic: 'topic1', secrets: { password: 'mypassword', ssl: { diff --git a/x-pack/plugins/index_lifecycle_management/common/types/index.ts b/x-pack/plugins/index_lifecycle_management/common/types/index.ts index bc7e881a8c23..ee5939e328ce 100644 --- a/x-pack/plugins/index_lifecycle_management/common/types/index.ts +++ b/x-pack/plugins/index_lifecycle_management/common/types/index.ts @@ -7,7 +7,7 @@ export * from './api'; -export * from './policies'; +export * from '@kbn/index-lifecycle-management-common-shared'; /** * These roles reflect how nodes are stratified into different data tiers. diff --git a/x-pack/plugins/index_lifecycle_management/public/locator.ts b/x-pack/plugins/index_lifecycle_management/public/locator.ts index 24599b6a6b47..382cbc4ad183 100644 --- a/x-pack/plugins/index_lifecycle_management/public/locator.ts +++ b/x-pack/plugins/index_lifecycle_management/public/locator.ts @@ -8,6 +8,7 @@ import type { SerializableRecord } from '@kbn/utility-types'; import { ManagementAppLocator } from '@kbn/management-plugin/common'; import { LocatorDefinition } from '@kbn/share-plugin/public'; +import { ILM_LOCATOR_ID } from '@kbn/index-lifecycle-management-common-shared'; import { getPoliciesListPath, getPolicyCreatePath, @@ -15,7 +16,7 @@ import { } from './application/services/navigation'; import { PLUGIN } from '../common/constants'; -export const ILM_LOCATOR_ID = 'ILM_LOCATOR_ID'; +export { ILM_LOCATOR_ID }; export interface IlmLocatorParams extends SerializableRecord { page: 'policies_list' | 'policy_edit' | 'policy_create'; diff --git a/x-pack/plugins/index_lifecycle_management/tsconfig.json b/x-pack/plugins/index_lifecycle_management/tsconfig.json index 7c3913fcae1b..08346dcdc2d3 100644 --- a/x-pack/plugins/index_lifecycle_management/tsconfig.json +++ b/x-pack/plugins/index_lifecycle_management/tsconfig.json @@ -41,6 +41,7 @@ "@kbn/react-kibana-context-render", "@kbn/unsaved-changes-prompt", "@kbn/shared-ux-table-persist", + "@kbn/index-lifecycle-management-common-shared", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/index_management/public/application/components/no_match/no_match.tsx b/x-pack/plugins/index_management/public/application/components/no_match/no_match.tsx index 7f5b3f4b4b7d..15e306bb396b 100644 --- a/x-pack/plugins/index_management/public/application/components/no_match/no_match.tsx +++ b/x-pack/plugins/index_management/public/application/components/no_match/no_match.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; import { CreateIndexButton } from '../../sections/home/index_list/create_index/create_index_button'; import { ExtensionsService } from '../../../services/extensions_service'; @@ -16,11 +17,13 @@ export const NoMatch = ({ filter, resetFilter, extensionsService, + share, }: { loadIndices: () => void; filter: string; resetFilter: () => void; extensionsService: ExtensionsService; + share?: SharePluginStart; }) => { if (filter) { return ( @@ -62,7 +65,7 @@ export const NoMatch = ({ if (extensionsService.emptyListContent) { return extensionsService.emptyListContent.renderContent({ - createIndexButton: , + createIndexButton: , }); } @@ -85,7 +88,7 @@ export const NoMatch = ({ />

    } - actions={} + actions={} /> ); }; diff --git a/x-pack/plugins/index_management/public/application/sections/home/index_list/create_index/create_index_button.tsx b/x-pack/plugins/index_management/public/application/sections/home/index_list/create_index/create_index_button.tsx index 746d684f48b7..e7201ce5d44b 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/index_list/create_index/create_index_button.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/index_list/create_index/create_index_button.tsx @@ -7,22 +7,32 @@ import React, { useState } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; import { EuiButton } from '@elastic/eui'; import { CreateIndexModal } from './create_index_modal'; -export const CreateIndexButton = ({ loadIndices }: { loadIndices: () => void }) => { +export interface CreateIndexButtonProps { + loadIndices: () => void; + share?: SharePluginStart; +} + +export const CreateIndexButton = ({ loadIndices, share }: CreateIndexButtonProps) => { const [createIndexModalOpen, setCreateIndexModalOpen] = useState(false); + const createIndexUrl = share?.url.locators.get('SEARCH_CREATE_INDEX')?.useUrl({}); + const actionProp = createIndexUrl + ? { href: createIndexUrl } + : { onClick: () => setCreateIndexModalOpen(true) }; return ( <> setCreateIndexModalOpen(true)} key="createIndexButton" data-test-subj="createIndexButton" data-telemetry-id="idxMgmt-indexList-createIndexButton" + {...actionProp} > - {({ services, config, core }) => { + {({ services, config, core, plugins }) => { const { extensionsService } = services; const { application, http } = core; + const { share } = plugins; const columnConfigs = getColumnConfigs({ showIndexStats: config.enableIndexStats, showSizeAndDocCount: config.enableSizeAndDocCount, @@ -669,7 +670,7 @@ export class IndexTable extends Component { )} - + @@ -714,6 +715,7 @@ export class IndexTable extends Component { filterChanged('')} extensionsService={extensionsService} diff --git a/x-pack/plugins/inference/kibana.jsonc b/x-pack/plugins/inference/kibana.jsonc index 6e4e389bdc5f..f184a848cf98 100644 --- a/x-pack/plugins/inference/kibana.jsonc +++ b/x-pack/plugins/inference/kibana.jsonc @@ -2,6 +2,8 @@ "type": "plugin", "id": "@kbn/inference-plugin", "owner": "@elastic/appex-ai-infra", + "group": "platform", + "visibility": "shared", "plugin": { "id": "inference", "server": true, diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/gsub.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/gsub.tsx index 7e72848485c1..8e12be6880d0 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/gsub.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/gsub.tsx @@ -37,7 +37,8 @@ const fieldsConfig: FieldsConfig = { validator: emptyField( i18n.translate('xpack.ingestPipelines.pipelineEditor.gsubForm.patternRequiredError', { defaultMessage: 'A value is required.', - }) + }), + false ), }, { diff --git a/x-pack/plugins/integration_assistant/kibana.jsonc b/x-pack/plugins/integration_assistant/kibana.jsonc index 94840008a334..66ee0775fb48 100644 --- a/x-pack/plugins/integration_assistant/kibana.jsonc +++ b/x-pack/plugins/integration_assistant/kibana.jsonc @@ -2,6 +2,8 @@ "type": "plugin", "id": "@kbn/integration-assistant-plugin", "owner": "@elastic/security-scalability", + "group": "platform", + "visibility": "shared", "description": "Plugin implementing the Integration Assistant API and UI", "plugin": { "id": "integrationAssistant", diff --git a/x-pack/plugins/kubernetes_security/public/test/index.tsx b/x-pack/plugins/kubernetes_security/public/test/index.tsx index a267169e6cf1..4aeaf93f746c 100644 --- a/x-pack/plugins/kubernetes_security/public/test/index.tsx +++ b/x-pack/plugins/kubernetes_security/public/test/index.tsx @@ -17,7 +17,7 @@ import { coreMock } from '@kbn/core/public/mocks'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; -type UiRender = (ui: React.ReactElement, options?: RenderOptions) => RenderResult; +type UiRender = (ui: React.ReactNode, options?: RenderOptions) => RenderResult; /** * Mocked app root context renderer @@ -113,7 +113,7 @@ export const createAppRootMockRenderer = (): AppContextTestRender => { }, }); - const AppWrapper: React.FC<{ children: React.ReactElement }> = ({ children }) => ( + const AppWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( {children} diff --git a/x-pack/plugins/lens/common/embeddable_factory/index.ts b/x-pack/plugins/lens/common/embeddable_factory/index.ts index b794ec642f40..68e6c77e9dae 100644 --- a/x-pack/plugins/lens/common/embeddable_factory/index.ts +++ b/x-pack/plugins/lens/common/embeddable_factory/index.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { cloneDeep } from 'lodash'; import type { SerializableRecord, Serializable } from '@kbn/utility-types'; import type { SavedObjectReference } from '@kbn/core/types'; import type { @@ -17,7 +18,8 @@ export type LensEmbeddablePersistableState = EmbeddableStateWithType & { }; export const inject: EmbeddableRegistryDefinition['inject'] = (state, references) => { - const typedState = state as LensEmbeddablePersistableState; + // We need to clone the state because we can not modify the original state object. + const typedState = cloneDeep(state) as LensEmbeddablePersistableState; if ('attributes' in typedState && typedState.attributes !== undefined) { // match references based on name, so only references associated with this lens panel are injected. diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/include_exclude_options.test.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/include_exclude_options.test.tsx index 87026e061329..8df04b23a543 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/include_exclude_options.test.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/include_exclude_options.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { fireEvent, render, screen, within } from '@testing-library/react'; +import { fireEvent, render, screen, within, act } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { IncludeExcludeRow, IncludeExcludeRowProps } from './include_exclude_options'; @@ -152,4 +152,168 @@ describe('IncludeExcludeComponent', () => { }); expect(onUpdateSpy).toHaveBeenCalledTimes(2); }); + + it('should prevent identical include and exclude values on change when making single selections', async () => { + renderIncludeExcludeRow({ + include: undefined, + exclude: undefined, + isNumberField: false, + tableRows, + }); + + await userEvent.click(screen.getByRole('combobox', { name: 'Include values' })); + await userEvent.click(screen.getByRole('option', { name: 'ABC' })); + expect(screen.getByTestId('lens-include-terms-combobox')).toHaveTextContent('ABC'); + + await userEvent.click(screen.getByRole('combobox', { name: 'Exclude values' })); + await userEvent.click(screen.getByRole('option', { name: 'ABC' })); + expect(screen.getByTestId('lens-exclude-terms-combobox')).toHaveTextContent('ABC'); + + expect(screen.getByTestId('lens-include-terms-combobox')).not.toHaveTextContent('ABC'); + + expect(onUpdateSpy).toHaveBeenCalledTimes(3); + }); + + it('should prevent identical include and exclude values on change when making multiple selections', async () => { + renderIncludeExcludeRow({ + include: undefined, + exclude: undefined, + isNumberField: false, + tableRows, + }); + + await userEvent.click(screen.getByRole('combobox', { name: 'Include values' })); + await userEvent.click(screen.getByRole('option', { name: 'ABC' })); + expect(screen.getByTestId('lens-include-terms-combobox')).toHaveTextContent('ABC'); + + await userEvent.click(screen.getByRole('combobox', { name: 'Include values' })); + await userEvent.click(screen.getByRole('option', { name: 'FEF' })); + expect(screen.getByTestId('lens-include-terms-combobox')).toHaveTextContent('FEF'); + + await userEvent.click(screen.getByRole('combobox', { name: 'Exclude values' })); + await userEvent.click(screen.getByRole('option', { name: 'ABC' })); + expect(screen.getByTestId('lens-include-terms-combobox')).not.toHaveTextContent('ABC'); + + expect(screen.getByTestId('lens-exclude-terms-combobox')).toHaveTextContent('ABC'); + + expect(onUpdateSpy).toHaveBeenCalledTimes(4); + }); + + it('should prevent identical include and exclude values on create option', async () => { + renderIncludeExcludeRow({ + include: undefined, + exclude: undefined, + isNumberField: false, + tableRows, + }); + + await userEvent.click(screen.getByRole('combobox', { name: 'Include values' })); + await userEvent.type(screen.getByRole('combobox', { name: 'Include values' }), 'test{enter}'); + expect(screen.getByTestId('lens-include-terms-combobox')).toHaveTextContent('test'); + + await userEvent.click(screen.getByRole('combobox', { name: 'Exclude values' })); + await userEvent.type(screen.getByRole('combobox', { name: 'Exclude values' }), 'test{enter}'); + expect(screen.getByTestId('lens-exclude-terms-combobox')).toHaveTextContent('test'); + + expect(screen.getByTestId('lens-include-terms-combobox')).not.toHaveTextContent('test'); + + expect(onUpdateSpy).toHaveBeenCalledTimes(3); + }); + + it('should prevent identical include and exclude values when creating multiple options', async () => { + renderIncludeExcludeRow({ + include: undefined, + exclude: undefined, + isNumberField: false, + tableRows, + }); + + await userEvent.click(screen.getByRole('combobox', { name: 'Include values' })); + await userEvent.type(screen.getByRole('combobox', { name: 'Include values' }), 'test{enter}'); + expect(screen.getByTestId('lens-include-terms-combobox')).toHaveTextContent('test'); + + await userEvent.type(screen.getByRole('combobox', { name: 'Include values' }), 'test1{enter}'); + expect(screen.getByTestId('lens-include-terms-combobox')).toHaveTextContent('test1'); + + await userEvent.click(screen.getByRole('combobox', { name: 'Exclude values' })); + await userEvent.type(screen.getByRole('combobox', { name: 'Exclude values' }), 'test1{enter}'); + expect(screen.getByTestId('lens-exclude-terms-combobox')).toHaveTextContent('test1'); + + expect(screen.getByTestId('lens-include-terms-combobox')).not.toHaveTextContent('test1'); + + expect(onUpdateSpy).toHaveBeenCalledTimes(4); + }); + + it('should prevent identical include value on exclude regex value change', async () => { + jest.useFakeTimers(); + + renderIncludeExcludeRow({ + include: [''], + exclude: [''], + includeIsRegex: true, + excludeIsRegex: true, + tableRows, + }); + + const includeRegexInput = screen.getByTestId('lens-include-terms-regex-input'); + const excludeRegexInput = screen.getByTestId('lens-exclude-terms-regex-input'); + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + + await user.type(includeRegexInput, 'test.*'); + act(() => { + jest.advanceTimersByTime(256); + }); + expect(includeRegexInput).toHaveValue('test.*'); + expect(onUpdateSpy).toHaveBeenCalledWith('include', ['test.*'], 'includeIsRegex', true); + + await user.type(excludeRegexInput, 'test.*'); + act(() => { + jest.advanceTimersByTime(256); + }); + expect(excludeRegexInput).toHaveValue('test.*'); + expect(onUpdateSpy).toHaveBeenCalledWith('exclude', ['test.*'], 'excludeIsRegex', true); + + expect(includeRegexInput).toHaveValue(''); + expect(onUpdateSpy).toHaveBeenCalledWith('include', [''], 'includeIsRegex', true); + + expect(onUpdateSpy).toHaveBeenCalledTimes(3); + + jest.useRealTimers(); + }); + + it('should prevent identical exclude value on include regex value change', async () => { + jest.useFakeTimers(); + + renderIncludeExcludeRow({ + include: [''], + exclude: [''], + includeIsRegex: true, + excludeIsRegex: true, + tableRows, + }); + + const includeRegexInput = screen.getByTestId('lens-include-terms-regex-input'); + const excludeRegexInput = screen.getByTestId('lens-exclude-terms-regex-input'); + const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); + + await user.type(excludeRegexInput, 'test.*'); + act(() => { + jest.advanceTimersByTime(256); + }); + expect(excludeRegexInput).toHaveValue('test.*'); + expect(onUpdateSpy).toHaveBeenCalledWith('exclude', ['test.*'], 'excludeIsRegex', true); + + await user.type(includeRegexInput, 'test.*'); + act(() => { + jest.advanceTimersByTime(256); + }); + expect(includeRegexInput).toHaveValue('test.*'); + expect(onUpdateSpy).toHaveBeenCalledWith('include', ['test.*'], 'includeIsRegex', true); + + expect(excludeRegexInput).toHaveValue(''); + expect(onUpdateSpy).toHaveBeenCalledWith('exclude', [''], 'excludeIsRegex', true); + + expect(onUpdateSpy).toHaveBeenCalledTimes(3); + jest.useRealTimers(); + }); }); diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/include_exclude_options.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/include_exclude_options.tsx index 41f521088af9..b2a8abb62c1a 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/include_exclude_options.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/include_exclude_options.tsx @@ -99,68 +99,77 @@ export const IncludeExcludeRow = ({ selectedOptions: IncludeExcludeOptions[], operation: 'include' | 'exclude' ) => { - const options = { - ...includeExcludeSelectedOptions, - [operation]: selectedOptions, - }; - setIncludeExcludeSelectedOptions(options); - const terms = selectedOptions.map((option) => { - if (!Number.isNaN(Number(option.label))) { - return Number(option.label); - } - return option.label; + const otherOperation = operation === 'include' ? 'exclude' : 'include'; + const otherSelectedOptions = includeExcludeSelectedOptions[otherOperation] ?? []; + const hasIdenticalOptions = selectedOptions.some((option) => { + return otherSelectedOptions.some((otherOption) => otherOption.label === option.label); }); - const param = `${operation}IsRegex`; - updateParams(operation, terms, param, false); - }; - - const onCreateOption = ( - searchValue: string, - flattenedOptions: IncludeExcludeOptions[] = [], - operation: 'include' | 'exclude' - ) => { - const newOption = { - label: searchValue, - }; - let includeExcludeOptions = []; + const otherSelectedNonIdenticalOptions = hasIdenticalOptions + ? otherSelectedOptions.filter( + (otherOption) => !selectedOptions.some((option) => option.label === otherOption.label) + ) + : otherSelectedOptions; - const includeORExcludeSelectedOptions = includeExcludeSelectedOptions[operation] ?? []; - includeExcludeOptions = [...includeORExcludeSelectedOptions, newOption]; const options = { - ...includeExcludeSelectedOptions, - [operation]: includeExcludeOptions, + [otherOperation]: otherSelectedNonIdenticalOptions, + [operation]: selectedOptions, }; setIncludeExcludeSelectedOptions(options); - const terms = includeExcludeOptions.map((option) => { - if (!Number.isNaN(Number(option.label))) { - return Number(option.label); - } - return option.label; - }); + const getTerms = (updatedSelectedOptions: IncludeExcludeOptions[]) => + updatedSelectedOptions.map((option) => { + if (!Number.isNaN(Number(option.label))) { + return Number(option.label); + } + return option.label; + }); + + const terms = getTerms(selectedOptions); const param = `${operation}IsRegex`; updateParams(operation, terms, param, false); + + if (hasIdenticalOptions) { + const otherTerms = getTerms(otherSelectedNonIdenticalOptions); + const otherParam = `${otherOperation}IsRegex`; + updateParams(otherOperation, otherTerms, otherParam, false); + } + }; + + const onCreateOption = (searchValue: string, operation: 'include' | 'exclude') => { + const newOption = { label: searchValue }; + const selectedOptions = [...(includeExcludeSelectedOptions[operation] ?? []), newOption]; + onChangeIncludeExcludeOptions(selectedOptions, operation); }; const onIncludeRegexChangeToDebounce = useCallback( (newIncludeValue: string | number | undefined) => { + const isEqualToExcludeValue = newIncludeValue === regex.exclude; + const excludeValue = isEqualToExcludeValue ? '' : regex.exclude; setRegex({ - ...regex, + exclude: excludeValue, include: newIncludeValue, }); updateParams('include', [newIncludeValue ?? ''], 'includeIsRegex', true); + if (isEqualToExcludeValue) { + updateParams('exclude', [''], 'excludeIsRegex', true); + } }, [regex, updateParams] ); const onExcludeRegexChangeToDebounce = useCallback( (newExcludeValue: string | number | undefined) => { + const isEqualToIncludeValue = newExcludeValue === regex.include; + const includeValue = isEqualToIncludeValue ? '' : regex.include; setRegex({ - ...regex, + include: includeValue, exclude: newExcludeValue, }); updateParams('exclude', [newExcludeValue ?? ''], 'excludeIsRegex', true); + if (isEqualToIncludeValue) { + updateParams('include', [''], 'includeIsRegex', true); + } }, [regex, updateParams] ); @@ -247,9 +256,7 @@ export const IncludeExcludeRow = ({ options={termsOptions} selectedOptions={includeExcludeSelectedOptions.include} onChange={(options) => onChangeIncludeExcludeOptions(options, 'include')} - onCreateOption={(searchValue, options) => - onCreateOption(searchValue, options, 'include') - } + onCreateOption={(searchValue) => onCreateOption(searchValue, 'include')} isClearable={true} data-test-subj="lens-include-terms-combobox" autoFocus @@ -300,6 +307,7 @@ export const IncludeExcludeRow = ({ defaultMessage: 'Enter a regex to filter values', } )} + data-test-subj="lens-exclude-terms-regex-input" value={excludeRegexValue} onChange={(e) => { onExcludeRegexValueChange(e.target.value); @@ -322,9 +330,7 @@ export const IncludeExcludeRow = ({ options={termsOptions} selectedOptions={includeExcludeSelectedOptions.exclude} onChange={(options) => onChangeIncludeExcludeOptions(options, 'exclude')} - onCreateOption={(searchValue, options) => - onCreateOption(searchValue, options, 'exclude') - } + onCreateOption={(searchValue) => onCreateOption(searchValue, 'exclude')} isClearable={true} data-test-subj="lens-exclude-terms-combobox" autoFocus diff --git a/x-pack/plugins/licensing/server/routes/feature_usage.ts b/x-pack/plugins/licensing/server/routes/feature_usage.ts index 33317ab09cb9..acb3303834de 100644 --- a/x-pack/plugins/licensing/server/routes/feature_usage.ts +++ b/x-pack/plugins/licensing/server/routes/feature_usage.ts @@ -14,7 +14,16 @@ export function registerFeatureUsageRoute( getStartServices: StartServicesAccessor<{}, LicensingPluginStart> ) { router.get( - { path: '/api/licensing/feature_usage', validate: false }, + { + path: '/api/licensing/feature_usage', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, async (context, request, response) => { const [, , { featureUsage }] = await getStartServices(); return response.ok({ diff --git a/x-pack/plugins/licensing/server/routes/info.ts b/x-pack/plugins/licensing/server/routes/info.ts index 1cbc7b639896..c73508fac823 100644 --- a/x-pack/plugins/licensing/server/routes/info.ts +++ b/x-pack/plugins/licensing/server/routes/info.ts @@ -9,7 +9,16 @@ import { LicensingRouter } from '../types'; export function registerInfoRoute(router: LicensingRouter) { router.get( - { path: '/api/licensing/info', validate: false }, + { + path: '/api/licensing/info', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, async (context, request, response) => { return response.ok({ body: (await context.licensing).license, diff --git a/x-pack/plugins/licensing/server/routes/internal/notify_feature_usage.ts b/x-pack/plugins/licensing/server/routes/internal/notify_feature_usage.ts index a33cf4284245..c3c70243005e 100644 --- a/x-pack/plugins/licensing/server/routes/internal/notify_feature_usage.ts +++ b/x-pack/plugins/licensing/server/routes/internal/notify_feature_usage.ts @@ -12,6 +12,12 @@ export function registerNotifyFeatureUsageRoute(router: LicensingRouter) { router.post( { path: '/internal/licensing/feature_usage/notify', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { body: schema.object({ featureName: schema.string(), diff --git a/x-pack/plugins/licensing/server/routes/internal/register_feature.ts b/x-pack/plugins/licensing/server/routes/internal/register_feature.ts index 0c043c7c127a..6b35c32a266d 100644 --- a/x-pack/plugins/licensing/server/routes/internal/register_feature.ts +++ b/x-pack/plugins/licensing/server/routes/internal/register_feature.ts @@ -17,6 +17,12 @@ export function registerRegisterFeatureRoute( router.post( { path: '/internal/licensing/feature_usage/register', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { body: schema.arrayOf( schema.object({ diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx index e7bedcc7cf30..6bcb0fe6255c 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.tsx @@ -48,7 +48,7 @@ import { AutocompleteFieldMatchAnyComponent, AutocompleteFieldMatchComponent, AutocompleteFieldWildcardComponent, - FieldComponent, + EsFieldSelector, OperatorComponent, } from '@kbn/securitysolution-autocomplete'; import { @@ -207,7 +207,7 @@ export const BuilderEntryItem: React.FC = ({ (isFirst: boolean): JSX.Element => { const filteredIndexPatterns = getFilteredIndexPatterns(indexPattern, entry); const comboBox = ( - router.versioned .post({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: ENDPOINT_LIST_ITEM_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/create_endpoint_list_route.ts b/x-pack/plugins/lists/server/routes/create_endpoint_list_route.ts index b15658a40d7f..54887adba7df 100644 --- a/x-pack/plugins/lists/server/routes/create_endpoint_list_route.ts +++ b/x-pack/plugins/lists/server/routes/create_endpoint_list_route.ts @@ -27,10 +27,12 @@ export const createEndpointListRoute = (router: ListsPluginRouter): void => { router.versioned .post({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: ENDPOINT_LIST_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts index 7071ec6412a2..e5c6bfd09dfc 100644 --- a/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts @@ -25,10 +25,12 @@ export const createExceptionListItemRoute = (router: ListsPluginRouter): void => router.versioned .post({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: EXCEPTION_LIST_ITEM_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/create_exception_list_route.ts b/x-pack/plugins/lists/server/routes/create_exception_list_route.ts index a0c0568c31b8..c7e0a952743c 100644 --- a/x-pack/plugins/lists/server/routes/create_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/create_exception_list_route.ts @@ -22,10 +22,12 @@ export const createExceptionListRoute = (router: ListsPluginRouter): void => { router.versioned .post({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: EXCEPTION_LIST_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/delete_endpoint_list_item_route.ts b/x-pack/plugins/lists/server/routes/delete_endpoint_list_item_route.ts index 0262b747744e..ee7093bcc1c5 100644 --- a/x-pack/plugins/lists/server/routes/delete_endpoint_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_endpoint_list_item_route.ts @@ -25,10 +25,12 @@ export const deleteEndpointListItemRoute = (router: ListsPluginRouter): void => router.versioned .delete({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: ENDPOINT_LIST_ITEM_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts index d460610cd02b..d8eb32e9eeaf 100644 --- a/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts @@ -25,10 +25,12 @@ export const deleteExceptionListItemRoute = (router: ListsPluginRouter): void => router.versioned .delete({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: EXCEPTION_LIST_ITEM_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts b/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts index 938fc9b9bcc2..db6bb460cbd3 100644 --- a/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts @@ -21,10 +21,12 @@ export const deleteExceptionListRoute = (router: ListsPluginRouter): void => { router.versioned .delete({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: EXCEPTION_LIST_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/duplicate_exception_list_route.ts b/x-pack/plugins/lists/server/routes/duplicate_exception_list_route.ts index 38a51f12a7ed..308a2e4cd3a4 100644 --- a/x-pack/plugins/lists/server/routes/duplicate_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/duplicate_exception_list_route.ts @@ -21,10 +21,12 @@ export const duplicateExceptionsRoute = (router: ListsPluginRouter): void => { router.versioned .post({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: `${EXCEPTION_LIST_URL}/_duplicate`, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/export_exception_list_route.ts b/x-pack/plugins/lists/server/routes/export_exception_list_route.ts index 72ac56460433..8fdd7dbc5e39 100644 --- a/x-pack/plugins/lists/server/routes/export_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/export_exception_list_route.ts @@ -18,10 +18,12 @@ export const exportExceptionsRoute = (router: ListsPluginRouter): void => { router.versioned .post({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: `${EXCEPTION_LIST_URL}/_export`, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/find_endpoint_list_item_route.ts b/x-pack/plugins/lists/server/routes/find_endpoint_list_item_route.ts index 01539424b8d6..d54560fb6c92 100644 --- a/x-pack/plugins/lists/server/routes/find_endpoint_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/find_endpoint_list_item_route.ts @@ -21,10 +21,12 @@ export const findEndpointListItemRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: `${ENDPOINT_LIST_ITEM_URL}/_find`, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts index f0e4b5546df4..964a13296c80 100644 --- a/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts @@ -21,10 +21,12 @@ export const findExceptionListItemRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: `${EXCEPTION_LIST_ITEM_URL}/_find`, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/find_exception_list_route.ts b/x-pack/plugins/lists/server/routes/find_exception_list_route.ts index 93206b178e2d..43a890780013 100644 --- a/x-pack/plugins/lists/server/routes/find_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/find_exception_list_route.ts @@ -21,10 +21,12 @@ export const findExceptionListRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: `${EXCEPTION_LIST_URL}/_find`, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/import_exceptions_route.ts b/x-pack/plugins/lists/server/routes/import_exceptions_route.ts index af6a88254915..946f1a02ac85 100644 --- a/x-pack/plugins/lists/server/routes/import_exceptions_route.ts +++ b/x-pack/plugins/lists/server/routes/import_exceptions_route.ts @@ -35,9 +35,13 @@ export const importExceptionsRoute = (router: ListsPluginRouter, config: ConfigT maxBytes: config.maxImportPayloadBytes, output: 'stream', }, - tags: ['access:lists-all'], }, path: `${EXCEPTION_LIST_URL}/_import`, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/internal/create_exception_filter_route.ts b/x-pack/plugins/lists/server/routes/internal/create_exception_filter_route.ts index 41c4e982a5b8..032951d7f750 100644 --- a/x-pack/plugins/lists/server/routes/internal/create_exception_filter_route.ts +++ b/x-pack/plugins/lists/server/routes/internal/create_exception_filter_route.ts @@ -22,10 +22,12 @@ export const getExceptionFilterRoute = (router: ListsPluginRouter): void => { router.versioned .post({ access: 'internal', - options: { - tags: ['access:securitySolution'], - }, path: INTERNAL_EXCEPTION_FILTER, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/internal/create_exceptions_list_route.ts b/x-pack/plugins/lists/server/routes/internal/create_exceptions_list_route.ts index 2ca2333333c7..325c54577762 100644 --- a/x-pack/plugins/lists/server/routes/internal/create_exceptions_list_route.ts +++ b/x-pack/plugins/lists/server/routes/internal/create_exceptions_list_route.ts @@ -20,13 +20,12 @@ export const internalCreateExceptionListRoute = (router: ListsPluginRouter): voi router.versioned .post({ access: 'internal', - options: { - // Access control is set to `read` on purpose, as this route is internal and meant to - // ensure we have lists created (if not already) for Endpoint artifacts in order to support - // the UI. The Schema ensures that only endpoint artifact list IDs are allowed. - tags: ['access:lists-read'], - }, path: INTERNAL_EXCEPTIONS_LIST_ENSURE_CREATED_URL, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/internal/find_lists_by_size_route.ts b/x-pack/plugins/lists/server/routes/internal/find_lists_by_size_route.ts index 3b0bc716cade..f8e5fc23e2e1 100644 --- a/x-pack/plugins/lists/server/routes/internal/find_lists_by_size_route.ts +++ b/x-pack/plugins/lists/server/routes/internal/find_lists_by_size_route.ts @@ -23,10 +23,12 @@ export const findListsBySizeRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'internal', - options: { - tags: ['access:lists-read'], - }, path: INTERNAL_FIND_LISTS_BY_SIZE, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list/create_list_route.ts b/x-pack/plugins/lists/server/routes/list/create_list_route.ts index 9b4714e14720..23934bdfc792 100644 --- a/x-pack/plugins/lists/server/routes/list/create_list_route.ts +++ b/x-pack/plugins/lists/server/routes/list/create_list_route.ts @@ -18,10 +18,12 @@ export const createListRoute = (router: ListsPluginRouter): void => { router.versioned .post({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: LIST_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list/delete_list_route.ts b/x-pack/plugins/lists/server/routes/list/delete_list_route.ts index 66c8cb2ee450..51877b511aca 100644 --- a/x-pack/plugins/lists/server/routes/list/delete_list_route.ts +++ b/x-pack/plugins/lists/server/routes/list/delete_list_route.ts @@ -30,10 +30,12 @@ export const deleteListRoute = (router: ListsPluginRouter): void => { router.versioned .delete({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: LIST_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list/import_list_item_route.ts b/x-pack/plugins/lists/server/routes/list/import_list_item_route.ts index f3f52828f787..cbe0816c2366 100644 --- a/x-pack/plugins/lists/server/routes/list/import_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list/import_list_item_route.ts @@ -34,12 +34,16 @@ export const importListItemRoute = (router: ListsPluginRouter, config: ConfigTyp maxBytes: config.maxImportPayloadBytes, parse: false, }, - tags: ['access:lists-all'], timeout: { payload: config.importTimeout.asMilliseconds(), }, }, path: `${LIST_ITEM_URL}/_import`, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list/patch_list_route.ts b/x-pack/plugins/lists/server/routes/list/patch_list_route.ts index 90855ed96885..369084cc21a2 100644 --- a/x-pack/plugins/lists/server/routes/list/patch_list_route.ts +++ b/x-pack/plugins/lists/server/routes/list/patch_list_route.ts @@ -18,10 +18,12 @@ export const patchListRoute = (router: ListsPluginRouter): void => { router.versioned .patch({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: LIST_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list/read_list_route.ts b/x-pack/plugins/lists/server/routes/list/read_list_route.ts index fff8ef9e6097..7fa6d20867be 100644 --- a/x-pack/plugins/lists/server/routes/list/read_list_route.ts +++ b/x-pack/plugins/lists/server/routes/list/read_list_route.ts @@ -18,10 +18,12 @@ export const readListRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: LIST_URL, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list/update_list_route.ts b/x-pack/plugins/lists/server/routes/list/update_list_route.ts index cf8e0dc4de83..a09c91b86937 100644 --- a/x-pack/plugins/lists/server/routes/list/update_list_route.ts +++ b/x-pack/plugins/lists/server/routes/list/update_list_route.ts @@ -18,10 +18,12 @@ export const updateListRoute = (router: ListsPluginRouter): void => { router.versioned .put({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: LIST_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list_index/create_list_index_route.ts b/x-pack/plugins/lists/server/routes/list_index/create_list_index_route.ts index 5842d7032a8b..1881e51c5888 100644 --- a/x-pack/plugins/lists/server/routes/list_index/create_list_index_route.ts +++ b/x-pack/plugins/lists/server/routes/list_index/create_list_index_route.ts @@ -17,10 +17,12 @@ export const createListIndexRoute = (router: ListsPluginRouter): void => { router.versioned .post({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: LIST_INDEX, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion({ validate: false, version: '2023-10-31' }, async (context, _, response) => { const siemResponse = buildSiemResponse(response); diff --git a/x-pack/plugins/lists/server/routes/list_index/delete_list_index_route.ts b/x-pack/plugins/lists/server/routes/list_index/delete_list_index_route.ts index 0814739ab11e..bb1801c29eb3 100644 --- a/x-pack/plugins/lists/server/routes/list_index/delete_list_index_route.ts +++ b/x-pack/plugins/lists/server/routes/list_index/delete_list_index_route.ts @@ -34,10 +34,12 @@ export const deleteListIndexRoute = (router: ListsPluginRouter): void => { router.versioned .delete({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: LIST_INDEX, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list_index/export_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_index/export_list_item_route.ts index 94cacc2f89c4..0c66787b8073 100644 --- a/x-pack/plugins/lists/server/routes/list_index/export_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_index/export_list_item_route.ts @@ -20,10 +20,12 @@ export const exportListItemRoute = (router: ListsPluginRouter): void => { router.versioned .post({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: `${LIST_ITEM_URL}/_export`, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list_index/find_list_route.ts b/x-pack/plugins/lists/server/routes/list_index/find_list_route.ts index 2bdbcc523936..13dd137a3d84 100644 --- a/x-pack/plugins/lists/server/routes/list_index/find_list_route.ts +++ b/x-pack/plugins/lists/server/routes/list_index/find_list_route.ts @@ -18,10 +18,12 @@ export const findListRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: `${LIST_URL}/_find`, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list_index/read_list_index_route.ts b/x-pack/plugins/lists/server/routes/list_index/read_list_index_route.ts index 79c82e739ebe..2cbe90aa3c81 100644 --- a/x-pack/plugins/lists/server/routes/list_index/read_list_index_route.ts +++ b/x-pack/plugins/lists/server/routes/list_index/read_list_index_route.ts @@ -17,10 +17,12 @@ export const readListIndexRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: LIST_INDEX, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list_item/create_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_item/create_list_item_route.ts index e5b1b15ef10d..b43b5e258d42 100644 --- a/x-pack/plugins/lists/server/routes/list_item/create_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_item/create_list_item_route.ts @@ -21,10 +21,12 @@ export const createListItemRoute = (router: ListsPluginRouter): void => { router.versioned .post({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: LIST_ITEM_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list_item/delete_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_item/delete_list_item_route.ts index 4cf9dd4d9691..94c6b17f28d4 100644 --- a/x-pack/plugins/lists/server/routes/list_item/delete_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_item/delete_list_item_route.ts @@ -21,10 +21,12 @@ export const deleteListItemRoute = (router: ListsPluginRouter): void => { router.versioned .delete({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: LIST_ITEM_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list_item/find_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_item/find_list_item_route.ts index 6bfd673f8fbc..5ed305de7ec8 100644 --- a/x-pack/plugins/lists/server/routes/list_item/find_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_item/find_list_item_route.ts @@ -21,10 +21,12 @@ export const findListItemRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: `${LIST_ITEM_URL}/_find`, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list_item/patch_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_item/patch_list_item_route.ts index 3545516e17f3..ef9290bc2ef3 100644 --- a/x-pack/plugins/lists/server/routes/list_item/patch_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_item/patch_list_item_route.ts @@ -21,10 +21,12 @@ export const patchListItemRoute = (router: ListsPluginRouter): void => { router.versioned .patch({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: LIST_ITEM_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list_item/read_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_item/read_list_item_route.ts index 29513aa23f74..421108552b7b 100644 --- a/x-pack/plugins/lists/server/routes/list_item/read_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_item/read_list_item_route.ts @@ -21,10 +21,12 @@ export const readListItemRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: LIST_ITEM_URL, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list_item/update_list_item_route.ts b/x-pack/plugins/lists/server/routes/list_item/update_list_item_route.ts index 408391ca63f1..14c992870e92 100644 --- a/x-pack/plugins/lists/server/routes/list_item/update_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/list_item/update_list_item_route.ts @@ -21,10 +21,12 @@ export const updateListItemRoute = (router: ListsPluginRouter): void => { router.versioned .put({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: LIST_ITEM_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/list_privileges/read_list_privileges_route.ts b/x-pack/plugins/lists/server/routes/list_privileges/read_list_privileges_route.ts index 94c171a2ec79..bf322d10cfc8 100644 --- a/x-pack/plugins/lists/server/routes/list_privileges/read_list_privileges_route.ts +++ b/x-pack/plugins/lists/server/routes/list_privileges/read_list_privileges_route.ts @@ -16,10 +16,12 @@ export const readPrivilegesRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: LIST_PRIVILEGES_URL, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/read_endpoint_list_item_route.ts b/x-pack/plugins/lists/server/routes/read_endpoint_list_item_route.ts index d7e057a70d5d..2f607d4c4c33 100644 --- a/x-pack/plugins/lists/server/routes/read_endpoint_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/read_endpoint_list_item_route.ts @@ -25,10 +25,12 @@ export const readEndpointListItemRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: ENDPOINT_LIST_ITEM_URL, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts index 9f35da7fa6fe..ceb0195c390a 100644 --- a/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts @@ -25,10 +25,12 @@ export const readExceptionListItemRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: EXCEPTION_LIST_ITEM_URL, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/read_exception_list_route.ts b/x-pack/plugins/lists/server/routes/read_exception_list_route.ts index b98b7dfe86ee..2ff46ffba56f 100644 --- a/x-pack/plugins/lists/server/routes/read_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/read_exception_list_route.ts @@ -21,10 +21,12 @@ export const readExceptionListRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'public', - options: { - tags: ['access:lists-read'], - }, path: EXCEPTION_LIST_URL, + security: { + authz: { + requiredPrivileges: ['lists-read'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/summary_exception_list_route.ts b/x-pack/plugins/lists/server/routes/summary_exception_list_route.ts index 28810283770b..bf5fe000a7fb 100644 --- a/x-pack/plugins/lists/server/routes/summary_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/summary_exception_list_route.ts @@ -21,10 +21,12 @@ export const summaryExceptionListRoute = (router: ListsPluginRouter): void => { router.versioned .get({ access: 'public', - options: { - tags: ['access:lists-summary'], - }, path: `${EXCEPTION_LIST_URL}/summary`, + security: { + authz: { + requiredPrivileges: ['lists-summary'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/update_endpoint_list_item_route.ts b/x-pack/plugins/lists/server/routes/update_endpoint_list_item_route.ts index 048816c519a0..a6c633ab57c3 100644 --- a/x-pack/plugins/lists/server/routes/update_endpoint_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/update_endpoint_list_item_route.ts @@ -23,10 +23,12 @@ export const updateEndpointListItemRoute = (router: ListsPluginRouter): void => router.versioned .put({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: ENDPOINT_LIST_ITEM_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts index f3f925317afb..da1541bb8617 100644 --- a/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts @@ -24,10 +24,12 @@ export const updateExceptionListItemRoute = (router: ListsPluginRouter): void => router.versioned .put({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: EXCEPTION_LIST_ITEM_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts index 6998b612c78a..36d65d9b1ac5 100644 --- a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts @@ -21,10 +21,12 @@ export const updateExceptionListRoute = (router: ListsPluginRouter): void => { router.versioned .put({ access: 'public', - options: { - tags: ['access:lists-all'], - }, path: EXCEPTION_LIST_URL, + security: { + authz: { + requiredPrivileges: ['lists-all'], + }, + }, }) .addVersion( { diff --git a/x-pack/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.ts b/x-pack/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.ts index 0a3632efe919..abdffd19eca7 100644 --- a/x-pack/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.ts +++ b/x-pack/plugins/lists/server/services/utils/transform_elastic_named_search_to_list_item.ts @@ -34,7 +34,7 @@ export const transformElasticNamedSearchToListItem = ({ }: TransformElasticMSearchToListItemOptions): SearchListItemArraySchema => { return value.map((singleValue, index) => { const matchingHits = response.hits.hits.filter((hit) => { - if (hit.matched_queries != null) { + if (hit.matched_queries != null && Array.isArray(hit.matched_queries)) { return hit.matched_queries.some((matchedQuery) => { const [matchedQueryIndex] = matchedQuery.split('.'); return matchedQueryIndex === `${index}`; diff --git a/x-pack/plugins/ml/public/application/_index.scss b/x-pack/plugins/ml/public/application/_index.scss index 3025b8f7d921..95fbbf4cb112 100644 --- a/x-pack/plugins/ml/public/application/_index.scss +++ b/x-pack/plugins/ml/public/application/_index.scss @@ -11,7 +11,6 @@ // Components @import 'components/annotations/annotation_description_list/index'; // SASSTODO: This file overwrites EUI directly @import 'components/anomalies_table/index'; // SASSTODO: This file overwrites EUI directly - @import 'components/color_range_legend/index'; @import 'components/entity_cell/index'; @import 'components/influencers_list/index'; @import 'components/job_selector/index'; diff --git a/x-pack/plugins/ml/public/application/components/chart_tooltip/_chart_tooltip.scss b/x-pack/plugins/ml/public/application/components/chart_tooltip/_chart_tooltip.scss deleted file mode 100644 index 9f9f16dff7e1..000000000000 --- a/x-pack/plugins/ml/public/application/components/chart_tooltip/_chart_tooltip.scss +++ /dev/null @@ -1,47 +0,0 @@ -.mlChartTooltip { - @include euiToolTipStyle('s'); - @include euiFontSizeXS; - padding: 0; - transition: opacity $euiAnimSpeedNormal; - pointer-events: none; - user-select: none; - max-width: 512px; - - &__list { - margin: $euiSizeXS; - padding-bottom: $euiSizeXS; - } - - &__header { - font-weight: $euiFontWeightBold; - padding: $euiSizeXS ($euiSizeXS * 2); - margin-bottom: $euiSizeXS; - border-bottom: $euiBorderThin solid transparentize($euiBorderColor, .8); - } - - &__item { - display: flex; - padding: 3px; - box-sizing: border-box; - border-left: $euiSizeXS solid transparent; - } - - &__label { - min-width: 1px; - } - - &__value { - font-weight: $euiFontWeightBold; - text-align: right; - font-feature-settings: 'tnum'; - margin-left: 8px; - } - - &__rowHighlighted { - background-color: transparentize($euiColorGhost, .9); - } - - &--hidden { - opacity: 0; - } -} diff --git a/x-pack/plugins/ml/public/application/components/chart_tooltip/_index.scss b/x-pack/plugins/ml/public/application/components/chart_tooltip/_index.scss deleted file mode 100644 index 11b36a0a2100..000000000000 --- a/x-pack/plugins/ml/public/application/components/chart_tooltip/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'chart_tooltip'; \ No newline at end of file diff --git a/x-pack/plugins/ml/public/application/components/chart_tooltip/chart_tooltip.tsx b/x-pack/plugins/ml/public/application/components/chart_tooltip/chart_tooltip.tsx index 0c6fe9095f4e..f279175d0110 100644 --- a/x-pack/plugins/ml/public/application/components/chart_tooltip/chart_tooltip.tsx +++ b/x-pack/plugins/ml/public/application/components/chart_tooltip/chart_tooltip.tsx @@ -9,14 +9,14 @@ import type { FC } from 'react'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import classNames from 'classnames'; import TooltipTrigger from 'react-popper-tooltip'; +import type { ChildrenArg, TooltipTriggerProps } from 'react-popper-tooltip/dist/types'; + import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import type { TooltipValueFormatter } from '@elastic/charts'; -import './_index.scss'; - -import type { ChildrenArg, TooltipTriggerProps } from 'react-popper-tooltip/dist/types'; import type { ChartTooltipValue, TooltipData } from './chart_tooltip_service'; import { ChartTooltipService } from './chart_tooltip_service'; +import { useChartTooltipStyles } from './chart_tooltip_styles'; const renderHeader = (headerData?: ChartTooltipValue, formatter?: TooltipValueFormatter) => { if (!headerData) { @@ -30,17 +30,26 @@ const renderHeader = (headerData?: ChartTooltipValue, formatter?: TooltipValueFo * Pure component for rendering the tooltip content with a custom layout across the ML plugin. */ export const FormattedTooltip: FC<{ tooltipData: TooltipData }> = ({ tooltipData }) => { + const { + mlChartTooltip, + mlChartTooltipList, + mlChartTooltipHeader, + mlChartTooltipItem, + mlChartTooltipLabel, + mlChartTooltipValue, + } = useChartTooltipStyles(); + return ( -
    +
    {tooltipData.length > 0 && tooltipData[0].skipHeader === undefined && ( -
    {renderHeader(tooltipData[0])}
    +
    {renderHeader(tooltipData[0])}
    )} {tooltipData.length > 1 && ( -
    +
    {tooltipData .slice(1) .map(({ label, value, color, isHighlighted, seriesIdentifier, valueAccessor }) => { - const classes = classNames('mlChartTooltip__item', { + const classes = classNames({ // eslint-disable-next-line @typescript-eslint/naming-convention echTooltip__rowHighlighted: isHighlighted, }); @@ -52,16 +61,21 @@ export const FormattedTooltip: FC<{ tooltipData: TooltipData }> = ({ tooltipData return (
    - + {label} - + {renderValue} diff --git a/x-pack/plugins/ml/public/application/components/chart_tooltip/chart_tooltip_styles.ts b/x-pack/plugins/ml/public/application/components/chart_tooltip/chart_tooltip_styles.ts new file mode 100644 index 000000000000..c53bdb5242f3 --- /dev/null +++ b/x-pack/plugins/ml/public/application/components/chart_tooltip/chart_tooltip_styles.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { css } from '@emotion/react'; + +import { mathWithUnits, transparentize, useEuiTheme } from '@elastic/eui'; +// @ts-expect-error style types not defined +import { euiToolTipStyles } from '@elastic/eui/lib/components/tool_tip/tool_tip.styles'; + +import { useCurrentEuiThemeVars } from '@kbn/ml-kibana-theme'; + +import { useMlKibana } from '../../contexts/kibana'; + +export const useChartTooltipStyles = () => { + const euiThemeContext = useEuiTheme(); + const { + services: { theme }, + } = useMlKibana(); + const { euiTheme } = useCurrentEuiThemeVars(theme); + const euiStyles = euiToolTipStyles(euiThemeContext); + + return { + mlChartTooltip: css([ + euiStyles.euiToolTip, + { + fontSize: euiTheme.euiFontSizeXS, + padding: 0, + transition: `opacity ${euiTheme.euiAnimSpeedNormal}`, + pointerEvents: 'none', + userSelect: 'none', + maxWidth: '512px', + position: 'relative', + }, + ]), + mlChartTooltipList: css({ + margin: euiTheme.euiSizeXS, + paddingBottom: euiTheme.euiSizeXS, + }), + mlChartTooltipHeader: css({ + fontWeight: euiTheme.euiFontWeightBold, + padding: `${euiTheme.euiSizeXS} ${mathWithUnits(euiTheme.euiSizeS, (x) => x * 2)}`, + marginBottom: euiTheme.euiSizeXS, + borderBottom: `1px solid ${transparentize(euiTheme.euiBorderColor, 0.8)}`, + }), + mlChartTooltipItem: css({ + display: 'flex', + padding: '3px', + boxSizing: 'border-box', + borderLeft: `${euiTheme.euiSizeXS} solid transparent`, + }), + mlChartTooltipLabel: css({ + minWidth: '1px', + }), + mlChartTooltipValue: css({ + fontWeight: euiTheme.euiFontWeightBold, + textAlign: 'right', + fontFeatureSettings: 'tnum', + marginLeft: '8px', + }), + }; +}; diff --git a/x-pack/plugins/ml/public/application/components/collapsible_panel/collapsible_panel.tsx b/x-pack/plugins/ml/public/application/components/collapsible_panel/collapsible_panel.tsx index 903033481bd0..b33d056467d1 100644 --- a/x-pack/plugins/ml/public/application/components/collapsible_panel/collapsible_panel.tsx +++ b/x-pack/plugins/ml/public/application/components/collapsible_panel/collapsible_panel.tsx @@ -16,6 +16,7 @@ import { } from '@elastic/eui'; import type { PropsWithChildren } from 'react'; import React, { type FC } from 'react'; +import { i18n } from '@kbn/i18n'; import { PanelHeaderItems } from './panel_header_items'; import { useCurrentThemeVars } from '../../contexts/kibana'; @@ -24,6 +25,7 @@ export interface CollapsiblePanelProps { onToggle: (isOpen: boolean) => void; header: React.ReactElement; headerItems?: React.ReactElement[]; + ariaLabel: string; } export const CollapsiblePanel: FC> = ({ @@ -32,6 +34,7 @@ export const CollapsiblePanel: FC> = ({ children, header, headerItems, + ariaLabel, }) => { const { euiTheme } = useCurrentThemeVars(); @@ -51,6 +54,17 @@ export const CollapsiblePanel: FC> = ({ { diff --git a/x-pack/plugins/ml/public/application/components/color_range_legend/_color_range_legend.scss b/x-pack/plugins/ml/public/application/components/color_range_legend/_color_range_legend.scss deleted file mode 100644 index b164e605a248..000000000000 --- a/x-pack/plugins/ml/public/application/components/color_range_legend/_color_range_legend.scss +++ /dev/null @@ -1,18 +0,0 @@ -/* Overrides for d3/svg default styles */ -.mlColorRangeLegend { - text { - @include fontSize($euiFontSizeXS - 2px); - fill: $euiColorDarkShade; - } - - .axis path { - fill: none; - stroke: none; - } - - .axis line { - fill: none; - stroke: $euiColorMediumShade; - shape-rendering: crispEdges; - } -} diff --git a/x-pack/plugins/ml/public/application/components/color_range_legend/_index.scss b/x-pack/plugins/ml/public/application/components/color_range_legend/_index.scss deleted file mode 100644 index c7cd3faac0dc..000000000000 --- a/x-pack/plugins/ml/public/application/components/color_range_legend/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'color_range_legend'; diff --git a/x-pack/plugins/ml/public/application/components/color_range_legend/color_range_legend.tsx b/x-pack/plugins/ml/public/application/components/color_range_legend/color_range_legend.tsx index f6a301f5eacc..9c121853cf6b 100644 --- a/x-pack/plugins/ml/public/application/components/color_range_legend/color_range_legend.tsx +++ b/x-pack/plugins/ml/public/application/components/color_range_legend/color_range_legend.tsx @@ -7,12 +7,36 @@ import type { FC } from 'react'; import React, { useEffect, useRef } from 'react'; +import { css } from '@emotion/react'; import d3 from 'd3'; import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; +import { euiThemeVars } from '@kbn/ui-theme'; + const COLOR_RANGE_RESOLUTION = 10; +// Overrides for d3/svg default styles +const cssOverride = css({ + // Override default font size and color for axis + text: { + fontSize: `calc(${euiThemeVars.euiFontSizeXS} - 2px)`, + fill: euiThemeVars.euiColorDarkShade, + }, + // Override default styles for axis lines + '.axis': { + path: { + fill: 'none', + stroke: 'none', + }, + line: { + fill: 'none', + stroke: euiThemeVars.euiColorMediumShade, + shapeRendering: 'crispEdges', + }, + }, +}); + interface ColorRangeLegendProps { colorRange: (d: number) => string; justifyTicks?: boolean; @@ -65,7 +89,6 @@ export const ColorRangeLegend: FC = ({ const wrapper = d3 .select(d3Container.current) - .classed('mlColorRangeLegend', true) .attr('width', wrapperWidth) .attr('height', wrapperHeight) .append('g') @@ -144,7 +167,7 @@ export const ColorRangeLegend: FC = ({ - + ); diff --git a/x-pack/plugins/ml/public/application/components/custom_urls/custom_url_editor/utils.ts b/x-pack/plugins/ml/public/application/components/custom_urls/custom_url_editor/utils.ts index c154abb6f5f6..d2dff81c3262 100644 --- a/x-pack/plugins/ml/public/application/components/custom_urls/custom_url_editor/utils.ts +++ b/x-pack/plugins/ml/public/application/components/custom_urls/custom_url_editor/utils.ts @@ -285,13 +285,12 @@ async function buildDashboardUrlFromSettings( let query; // Override with filters and queries from saved dashboard if they are available. - const searchSourceJSON = dashboard.attributes.kibanaSavedObjectMeta.searchSourceJSON; - if (searchSourceJSON !== undefined) { - const searchSourceData = JSON.parse(searchSourceJSON); - if (Array.isArray(searchSourceData.filter) && searchSourceData.filter.length > 0) { - filters = searchSourceData.filter; + const { searchSource } = dashboard.attributes.kibanaSavedObjectMeta; + if (searchSource !== undefined) { + if (Array.isArray(searchSource.filter) && searchSource.filter.length > 0) { + filters = searchSource.filter; } - query = searchSourceData.query; + query = searchSource.query; } const queryFromEntityFieldNames = buildAppStateQueryParam(queryFieldNames ?? []); diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.scss b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.scss deleted file mode 100644 index 322cdb4971f0..000000000000 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.scss +++ /dev/null @@ -1,8 +0,0 @@ -.mlScatterplotMatrix { - overflow-x: auto; - - .vega-bind span { - font-size: $euiFontSizeXS; - padding: 0 $euiSizeXS; - } -} \ No newline at end of file diff --git a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx index dab7dc411708..763addd4aaa8 100644 --- a/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx +++ b/x-pack/plugins/ml/public/application/components/scatterplot_matrix/scatterplot_matrix.tsx @@ -7,6 +7,7 @@ import type { FC } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { css } from '@emotion/react'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { EuiComboBoxOptionOption } from '@elastic/eui'; @@ -35,6 +36,7 @@ import { type RuntimeMappings, } from '@kbn/ml-runtime-field-utils'; import { getProcessedFields } from '@kbn/ml-data-grid'; +import { euiThemeVars } from '@kbn/ui-theme'; import { useCurrentThemeVars, useMlApi, useMlKibana } from '../../contexts/kibana'; @@ -48,7 +50,17 @@ import { OUTLIER_SCORE_FIELD, } from './scatterplot_matrix_vega_lite_spec'; -import './scatterplot_matrix.scss'; +const cssOverrides = css({ + // Prevent the chart from overflowing the container + overflowX: 'auto', + // Overrides for the outlier threshold slider + '.vega-bind': { + span: { + fontSize: euiThemeVars.euiFontSizeXS, + padding: `0 ${euiThemeVars.euiSizeXS}`, + }, + }, +}); const SCATTERPLOT_MATRIX_DEFAULT_FIELDS = 4; const SCATTERPLOT_MATRIX_DEFAULT_FETCH_SIZE = 1000; @@ -413,7 +425,7 @@ export const ScatterplotMatrix: FC = ({ ) : (
    diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx index d8c20f7f3d6f..366debdc3fea 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/expandable_section/expandable_section_results.tsx @@ -337,7 +337,12 @@ export const ExpandableSectionResults: FC = ({ anchorPosition="upCenter" button={ setIsPopoverVisible(!isPopoverVisible)} 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 4c76ebe628f4..b9b680a9fbac 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 @@ -101,6 +101,9 @@ export const AlertsPanel: FC = () => { ); })} + ariaLabel={i18n.translate('xpack.ml.explorer.alertsPanel.ariaLabel', { + defaultMessage: 'alerts panel', + })} > diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/function_help.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/function_help.tsx index a72380828a6d..e93b446d486a 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/function_help.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/advanced_detector_modal/function_help.tsx @@ -28,7 +28,18 @@ export const FunctionHelpPopover = memo(() => { const onHelpClick = () => setIsHelpOpen((prevIsHelpOpen) => !prevIsHelpOpen); const closeHelp = () => setIsHelpOpen(false); - const helpButton = ; + const helpButton = ( + + ); const columns = [ { diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/detector_title/detector_title.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/detector_title/detector_title.tsx index d153ee2bf284..439bdc0c4e2f 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/detector_title/detector_title.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/detector_title/detector_title.tsx @@ -51,7 +51,12 @@ export const DetectorTitle: FC> = ({ onClick={() => deleteDetector(index)} iconType="cross" size="s" - aria-label="Next" + aria-label={i18n.translate( + 'xpack.ml.newJob.wizard.pickFieldsStep.nextButtonAriaLabel', + { + defaultMessage: 'Next', + } + )} /> )} 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 e9db6b4e4f59..f7e95e3eda52 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 @@ -182,6 +182,7 @@ export const ExpandedRow: FC = ({ item }) => { key: `${perDeploymentStat.deployment_id}_${nodeName}`, ...perDeploymentStat, ...modelSizeStats, + // @ts-expect-error `throughput_last_minute` is not declared in ES Types node: { ...pick(n, [ 'average_inference_time_ms', diff --git a/x-pack/plugins/ml/public/application/overview/components/analytics_panel/analytics_panel.tsx b/x-pack/plugins/ml/public/application/overview/components/analytics_panel/analytics_panel.tsx index c94f594f548c..176633ecfd3a 100644 --- a/x-pack/plugins/ml/public/application/overview/components/analytics_panel/analytics_panel.tsx +++ b/x-pack/plugins/ml/public/application/overview/components/analytics_panel/analytics_panel.tsx @@ -119,6 +119,9 @@ export const AnalyticsPanel: FC = ({ setLazyJobCount }) => { })} , ]} + ariaLabel={i18n.translate('xpack.ml.overview.analyticsListPanel.ariaLabel', { + defaultMessage: 'data frame analytics panel', + })} > {noDFAJobs ? : null} diff --git a/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx b/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx index 5e17304fff1c..42aca6f330a9 100644 --- a/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx +++ b/x-pack/plugins/ml/public/application/overview/components/anomaly_detection_panel/anomaly_detection_panel.tsx @@ -209,6 +209,9 @@ export const AnomalyDetectionPanel: FC = ({ anomalyTimelineService, setLa })} , ]} + ariaLabel={i18n.translate('xpack.ml.overview.adJobsPanel.ariaLabel', { + defaultMessage: 'anomaly detection panel', + })} > {noAdJobs ? : null} diff --git a/x-pack/plugins/ml/public/application/overview/overview_page.tsx b/x-pack/plugins/ml/public/application/overview/overview_page.tsx index c66bc6e1ea7e..57e453b15af7 100644 --- a/x-pack/plugins/ml/public/application/overview/overview_page.tsx +++ b/x-pack/plugins/ml/public/application/overview/overview_page.tsx @@ -112,6 +112,9 @@ export const OverviewPage: FC = () => { })} , ]} + ariaLabel={i18n.translate('xpack.ml.overview.nodesPanel.ariaLabel', { + defaultMessage: 'overview panel', + })} > diff --git a/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts b/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts index c7bf9ca8bc5d..aa8bb89c47ea 100644 --- a/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts +++ b/x-pack/plugins/ml/server/lib/ml_client/ml_client.ts @@ -615,10 +615,6 @@ export function getMlClient( p ); }, - async postData(...p: Parameters) { - await jobIdsCheck('anomaly-detector', p); - return mlClient.postData(...p); - }, async previewDatafeed(...p: Parameters) { await datafeedIdsCheck(p); return mlClient.previewDatafeed(...p); diff --git a/x-pack/plugins/ml/server/lib/ml_client/types.ts b/x-pack/plugins/ml/server/lib/ml_client/types.ts index ca7b36df8f20..d610baa92bc5 100644 --- a/x-pack/plugins/ml/server/lib/ml_client/types.ts +++ b/x-pack/plugins/ml/server/lib/ml_client/types.ts @@ -101,7 +101,6 @@ export type MlClientParams = | Parameters | Parameters | Parameters - | Parameters | Parameters | Parameters | Parameters diff --git a/x-pack/plugins/ml/server/models/model_management/memory_usage.ts b/x-pack/plugins/ml/server/models/model_management/memory_usage.ts index 6e2931dbbe06..6e9121a133bb 100644 --- a/x-pack/plugins/ml/server/models/model_management/memory_usage.ts +++ b/x-pack/plugins/ml/server/models/model_management/memory_usage.ts @@ -181,6 +181,7 @@ export class MemoryUsageService { const mlNodes = Object.entries(response.nodes).filter(([, node]) => node.roles.includes('ml')); + // @ts-expect-error `throughput_last_minute` is not declared in ES Types const nodeDeploymentStatsResponses: NodeDeploymentStatsResponse[] = mlNodes.map( ([nodeId, node]) => { const nodeFields = pick(node, NODE_FIELDS) as RequiredNodeFields; diff --git a/x-pack/plugins/monitoring_collection/kibana.jsonc b/x-pack/plugins/monitoring_collection/kibana.jsonc index c2df8e901532..0e779a6f532a 100644 --- a/x-pack/plugins/monitoring_collection/kibana.jsonc +++ b/x-pack/plugins/monitoring_collection/kibana.jsonc @@ -2,6 +2,8 @@ "type": "plugin", "id": "@kbn/monitoring-collection-plugin", "owner": "@elastic/stack-monitoring", + "group": "platform", + "visibility": "private", "plugin": { "id": "monitoringCollection", "server": true, diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/integration_settings/integration_policy.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/integration_settings/integration_policy.cy.ts index da9a08339a45..753e6476be1e 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/integration_settings/integration_policy.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/integration_settings/integration_policy.cy.ts @@ -28,7 +28,7 @@ const policyFormFields = [ }, ]; -describe('when navigating to integration page', () => { +describe.skip('when navigating to integration page', () => { beforeEach(() => { const integrationsPath = '/app/integrations/browse'; 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 0fc1b609b14b..730e9c443854 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 @@ -16,7 +16,7 @@ const timeRange = { rangeTo: end, }; // flaky -describe('Transaction details', () => { +describe.skip('Transaction details', () => { before(() => { synthtrace.index( opbeans({ diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/tutorial/tutorial.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/tutorial/tutorial.cy.ts deleted file mode 100644 index 9aa71604e6a8..000000000000 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/tutorial/tutorial.cy.ts +++ /dev/null @@ -1,37 +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. - */ - -describe('APM tutorial', () => { - beforeEach(() => { - cy.loginAsViewerUser(); - cy.visitKibana('/app/home#/tutorial/apm'); - }); - - it('includes section for APM Server', () => { - cy.contains('APM Server'); - cy.contains('Linux DEB'); - cy.contains('Linux RPM'); - cy.contains('Other Linux'); - cy.contains('macOS'); - cy.contains('Windows'); - cy.contains('Fleet'); - }); - - it('includes section for APM Agents', () => { - cy.contains('APM agents'); - cy.contains('Java'); - cy.contains('RUM'); - cy.contains('Node.js'); - cy.contains('Django'); - cy.contains('Flask'); - cy.contains('Ruby on Rails'); - cy.contains('Rack'); - cy.contains('Go'); - cy.contains('.NET'); - cy.contains('PHP'); - }); -}); diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/metrics/static_dashboard/dashboards/java.json b/x-pack/plugins/observability_solution/apm/public/components/app/metrics/static_dashboard/dashboards/java.json index 5d4810626836..35e4e13aba2b 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/metrics/static_dashboard/dashboards/java.json +++ b/x-pack/plugins/observability_solution/apm/public/components/app/metrics/static_dashboard/dashboards/java.json @@ -11,7 +11,7 @@ "searchSourceJSON": "{\"query\":{\"query\":\"agent.name : \\\"java\\\" \",\"language\":\"kuery\"},\"filter\":[]}" }, "optionsJSON": "{\"useMargins\":true,\"syncColors\":false,\"syncCursor\":true,\"syncTooltips\":false,\"hidePanelTitles\":false}", - "panelsJSON": "[{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":0,\"w\":48,\"h\":10,\"i\":\"7b6cce32-fe3c-47a3-8784-6646ee4d5b24\"},\"panelIndex\":\"7b6cce32-fe3c-47a3-8784-6646ee4d5b24\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsDatatable\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-ffdfcd10-9cab-4806-813b-5c1c5053584e\"}],\"state\":{\"visualization\":{\"columns\":[{\"columnId\":\"03bdc1b7-9f72-4d24-89ae-72014a51a251\",\"isTransposed\":false,\"oneClickFilter\":false},{\"columnId\":\"51804f56-a2e5-44fd-bb44-762d7071437a\",\"isTransposed\":false,\"colorMode\":\"text\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":5,\"stops\":[{\"color\":\"#209280\",\"stop\":0.5},{\"color\":\"#54b399\",\"stop\":0.7},{\"color\":\"#d6bf57\",\"stop\":0.8},{\"color\":\"#e7664c\",\"stop\":0.9},{\"color\":\"#cc5642\",\"stop\":1.9}],\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"name\":\"custom\",\"colorStops\":[{\"color\":\"#209280\",\"stop\":0},{\"color\":\"#54b399\",\"stop\":0.5},{\"color\":\"#d6bf57\",\"stop\":0.7},{\"color\":\"#e7664c\",\"stop\":0.8},{\"color\":\"#cc5642\",\"stop\":0.9}],\"continuity\":\"above\",\"reverse\":false}}},{\"columnId\":\"bc1e385f-8a20-4227-980c-ee1f462e9c5b\",\"isTransposed\":false},{\"columnId\":\"fc9f178f-1bf3-4ec9-b709-2cf563038d8b\",\"isTransposed\":false},{\"columnId\":\"fd3d4405-64dd-4bdd-b5a6-79a89e9d7730\",\"isTransposed\":false},{\"columnId\":\"8bf5c093-6115-4f73-a279-1dd576647e20\",\"isTransposed\":false},{\"columnId\":\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7d\",\"isTransposed\":false,\"colorMode\":\"text\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":5,\"stops\":[{\"color\":\"#209280\",\"stop\":0.6},{\"color\":\"#54b399\",\"stop\":0.7},{\"color\":\"#d6bf57\",\"stop\":0.8},{\"color\":\"#e7664c\",\"stop\":0.9},{\"color\":\"#cc5642\",\"stop\":1.9}],\"name\":\"custom\",\"colorStops\":[{\"color\":\"#209280\",\"stop\":0},{\"color\":\"#54b399\",\"stop\":0.6},{\"color\":\"#d6bf57\",\"stop\":0.7},{\"color\":\"#e7664c\",\"stop\":0.8},{\"color\":\"#cc5642\",\"stop\":0.9}],\"continuity\":\"above\",\"reverse\":false,\"rangeMin\":0,\"rangeMax\":null,\"rangeType\":\"number\"}}}],\"layerId\":\"ffdfcd10-9cab-4806-813b-5c1c5053584e\",\"layerType\":\"data\"},\"query\":{\"query\":\"agent.name: java\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"ffdfcd10-9cab-4806-813b-5c1c5053584e\":{\"columns\":{\"03bdc1b7-9f72-4d24-89ae-72014a51a251\":{\"label\":\"JVM (Top 10)\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"service.node.name\",\"isBucketed\":true,\"params\":{\"size\":10,\"orderBy\":{\"type\":\"column\",\"columnId\":\"51804f56-a2e5-44fd-bb44-762d7071437a\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false},\"customLabel\":true},\"51804f56-a2e5-44fd-bb44-762d7071437a\":{\"label\":\"CPU avg\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"system.cpu.total.norm.pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":1,\"compact\":false}}},\"customLabel\":true},\"bc1e385f-8a20-4227-980c-ee1f462e9c5b\":{\"label\":\"Heap memory avg\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":1}}},\"customLabel\":true},\"fc9f178f-1bf3-4ec9-b709-2cf563038d8b\":{\"label\":\"Non-heap memory avg\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.non_heap.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":1}}},\"customLabel\":true},\"fd3d4405-64dd-4bdd-b5a6-79a89e9d7730\":{\"label\":\"Thread count max\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"jvm.thread.count\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0}}},\"customLabel\":true},\"8bf5c093-6115-4f73-a279-1dd576647e20\":{\"label\":\"Host name\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"host.hostname\",\"isBucketed\":true,\"params\":{\"size\":1,\"orderBy\":{\"type\":\"column\",\"columnId\":\"51804f56-a2e5-44fd-bb44-762d7071437a\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false},\"customLabel\":true},\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX0\":{\"label\":\"Part of Heap avg [%]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX1\":{\"label\":\"Part of Heap avg [%]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.max\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX2\":{\"label\":\"Part of Heap avg [%]\",\"dataType\":\"number\",\"operationType\":\"math\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"tinymathAst\":{\"type\":\"function\",\"name\":\"divide\",\"args\":[\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX0\",\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX1\"],\"location\":{\"min\":0,\"max\":58},\"text\":\"average(jvm.memory.heap.used)/average(jvm.memory.heap.max)\"}},\"references\":[\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX0\",\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX1\"],\"customLabel\":true},\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7d\":{\"label\":\"Heap usage avg [%]\",\"dataType\":\"number\",\"operationType\":\"formula\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"formula\":\"average(jvm.memory.heap.used)/average(jvm.memory.heap.max)\",\"isFormulaBroken\":false,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":1}}},\"references\":[\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX2\"],\"customLabel\":true}},\"columnOrder\":[\"03bdc1b7-9f72-4d24-89ae-72014a51a251\",\"8bf5c093-6115-4f73-a279-1dd576647e20\",\"51804f56-a2e5-44fd-bb44-762d7071437a\",\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7d\",\"bc1e385f-8a20-4227-980c-ee1f462e9c5b\",\"fc9f178f-1bf3-4ec9-b709-2cf563038d8b\",\"fd3d4405-64dd-4bdd-b5a6-79a89e9d7730\",\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX0\",\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX1\",\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX2\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":10,\"w\":24,\"h\":15,\"i\":\"e0987960-239c-4bc4-85af-6d25e3f63607\"},\"panelIndex\":\"e0987960-239c-4bc4-85af-6d25e3f63607\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-f29b4866-f576-49a4-af42-efafad81d0ff\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"line\",\"layers\":[{\"layerId\":\"f29b4866-f576-49a4-af42-efafad81d0ff\",\"accessors\":[\"2cb44b2f-fff3-45e4-b40e-e067daf21b52\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767\",\"3ac12c4e-f2c9-4914-b461-1ec3e96ac6e7\",\"28a6e0b4-1f21-4b22-b006-aa2d8ff69b27\"],\"position\":\"top\",\"seriesType\":\"line\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"fd579e72-9688-4cc3-987a-814c255ef7a4\",\"yConfig\":[{\"forAccessor\":\"3ac12c4e-f2c9-4914-b461-1ec3e96ac6e7\",\"color\":\"#d6bf57\"},{\"forAccessor\":\"28a6e0b4-1f21-4b22-b006-aa2d8ff69b27\",\"color\":\"#da8b45\"}]}],\"yTitle\":\"Utilization [%]\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"f29b4866-f576-49a4-af42-efafad81d0ff\":{\"columns\":{\"fd579e72-9688-4cc3-987a-814c255ef7a4\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"2cb44b2f-fff3-45e4-b40e-e067daf21b52\":{\"label\":\"System average\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"system.cpu.total.norm.pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"customLabel\":true},\"2d12ce33-9691-4f4a-9717-eab6e4fed767\":{\"label\":\"System max\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"system.cpu.total.norm.pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"customLabel\":true},\"3ac12c4e-f2c9-4914-b461-1ec3e96ac6e7\":{\"label\":\"Process average\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"system.process.cpu.total.norm.pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"customLabel\":true},\"28a6e0b4-1f21-4b22-b006-aa2d8ff69b27\":{\"label\":\"Process max\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"system.process.cpu.total.norm.pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2,\"compact\":false}}},\"customLabel\":true}},\"columnOrder\":[\"fd579e72-9688-4cc3-987a-814c255ef7a4\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767\",\"3ac12c4e-f2c9-4914-b461-1ec3e96ac6e7\",\"28a6e0b4-1f21-4b22-b006-aa2d8ff69b27\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"CPU Usage\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":10,\"w\":24,\"h\":15,\"i\":\"02a5f484-9647-4559-8706-4b3f63b3f5e8\"},\"panelIndex\":\"02a5f484-9647-4559-8706-4b3f63b3f5e8\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-f29b4866-f576-49a4-af42-efafad81d0ff\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"line\",\"layers\":[{\"layerId\":\"f29b4866-f576-49a4-af42-efafad81d0ff\",\"accessors\":[\"2cb44b2f-fff3-45e4-b40e-e067daf21b52\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767\"],\"position\":\"top\",\"seriesType\":\"line\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"fd579e72-9688-4cc3-987a-814c255ef7a4\",\"yConfig\":[]}],\"yTitle\":\"Usage [%]\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"f29b4866-f576-49a4-af42-efafad81d0ff\":{\"columns\":{\"fd579e72-9688-4cc3-987a-814c255ef7a4\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X0\":{\"label\":\"Part of System average\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"system.memory.actual.free\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X1\":{\"label\":\"Part of System average\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"system.memory.total\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X2\":{\"label\":\"Part of System average\",\"dataType\":\"number\",\"operationType\":\"math\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"tinymathAst\":{\"type\":\"function\",\"name\":\"subtract\",\"args\":[1,{\"type\":\"function\",\"name\":\"divide\",\"args\":[\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X0\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X1\"],\"location\":{\"min\":3,\"max\":67},\"text\":\" average(system.memory.actual.free)/average(system.memory.total)\"}],\"location\":{\"min\":0,\"max\":67},\"text\":\"1 - average(system.memory.actual.free)/average(system.memory.total)\"}},\"references\":[\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X0\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X1\"],\"customLabel\":true},\"2cb44b2f-fff3-45e4-b40e-e067daf21b52\":{\"label\":\"Average\",\"dataType\":\"number\",\"operationType\":\"formula\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"formula\":\"1 - average(system.memory.actual.free)/average(system.memory.total)\",\"isFormulaBroken\":false,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"references\":[\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X2\"],\"customLabel\":true},\"2d12ce33-9691-4f4a-9717-eab6e4fed767X0\":{\"label\":\"Part of Max\",\"dataType\":\"number\",\"operationType\":\"min\",\"sourceField\":\"system.memory.actual.free\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"2d12ce33-9691-4f4a-9717-eab6e4fed767X1\":{\"label\":\"Part of Max\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"system.memory.total\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"2d12ce33-9691-4f4a-9717-eab6e4fed767X2\":{\"label\":\"Part of Max\",\"dataType\":\"number\",\"operationType\":\"math\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"tinymathAst\":{\"type\":\"function\",\"name\":\"subtract\",\"args\":[1,{\"type\":\"function\",\"name\":\"divide\",\"args\":[\"2d12ce33-9691-4f4a-9717-eab6e4fed767X0\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767X1\"],\"location\":{\"min\":3,\"max\":59},\"text\":\" min(system.memory.actual.free)/max(system.memory.total)\"}],\"location\":{\"min\":0,\"max\":59},\"text\":\"1 - min(system.memory.actual.free)/max(system.memory.total)\"}},\"references\":[\"2d12ce33-9691-4f4a-9717-eab6e4fed767X0\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767X1\"],\"customLabel\":true},\"2d12ce33-9691-4f4a-9717-eab6e4fed767\":{\"label\":\"Max\",\"dataType\":\"number\",\"operationType\":\"formula\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"formula\":\"1 - min(system.memory.actual.free)/max(system.memory.total)\",\"isFormulaBroken\":false,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"references\":[\"2d12ce33-9691-4f4a-9717-eab6e4fed767X2\"],\"customLabel\":true}},\"columnOrder\":[\"fd579e72-9688-4cc3-987a-814c255ef7a4\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X0\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X1\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X2\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767X0\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767X1\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767X2\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"System Memory Usage\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":25,\"w\":24,\"h\":15,\"i\":\"5e044c2f-a316-4180-8f21-571fec481377\"},\"panelIndex\":\"5e044c2f-a316-4180-8f21-571fec481377\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-7f101489-db13-43e3-a1cd-fc0e9117361a\"},{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-2df2bccd-257b-4ec4-ba84-b022128ff511\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\",\"maxLines\":1,\"showSingleSeries\":true,\"shouldTruncate\":true,\"isInside\":false},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"yTitle\":\"Usage [bytes]\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"area\",\"layers\":[{\"layerId\":\"7f101489-db13-43e3-a1cd-fc0e9117361a\",\"accessors\":[\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\",\"7d04d69b-99a3-462c-b4fd-0b51bd50a508\"],\"position\":\"top\",\"seriesType\":\"area\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\"},{\"layerId\":\"2df2bccd-257b-4ec4-ba84-b022128ff511\",\"layerType\":\"data\",\"accessors\":[\"8cbe1326-c46a-437b-ad96-5fb9feefa997\"],\"seriesType\":\"line\",\"xAccessor\":\"51a76fb0-bc4e-4c0c-aa43-38b96b8778a0\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"7f101489-db13-43e3-a1cd-fc0e9117361a\":{\"columns\":{\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\":{\"label\":\"Avg. committed\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.committed\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}}},\"customLabel\":true},\"7d04d69b-99a3-462c-b4fd-0b51bd50a508\":{\"label\":\"Avg. used\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}}},\"customLabel\":true}},\"columnOrder\":[\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\",\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\",\"7d04d69b-99a3-462c-b4fd-0b51bd50a508\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}},\"2df2bccd-257b-4ec4-ba84-b022128ff511\":{\"linkToLayers\":[],\"columns\":{\"51a76fb0-bc4e-4c0c-aa43-38b96b8778a0\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"8cbe1326-c46a-437b-ad96-5fb9feefa997\":{\"label\":\"Limit\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.max\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}}},\"customLabel\":true}},\"columnOrder\":[\"51a76fb0-bc4e-4c0c-aa43-38b96b8778a0\",\"8cbe1326-c46a-437b-ad96-5fb9feefa997\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Heap memory usage\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":25,\"w\":24,\"h\":15,\"i\":\"5dd8b3f8-67f4-41d3-84f2-37d20d0f4020\"},\"panelIndex\":\"5dd8b3f8-67f4-41d3-84f2-37d20d0f4020\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-7f101489-db13-43e3-a1cd-fc0e9117361a\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\",\"maxLines\":1,\"showSingleSeries\":true,\"shouldTruncate\":true,\"isInside\":false},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"yTitle\":\"Usage [bytes]\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"area\",\"layers\":[{\"layerId\":\"7f101489-db13-43e3-a1cd-fc0e9117361a\",\"accessors\":[\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\",\"7d04d69b-99a3-462c-b4fd-0b51bd50a508\"],\"position\":\"top\",\"seriesType\":\"area\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"7f101489-db13-43e3-a1cd-fc0e9117361a\":{\"columns\":{\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\":{\"label\":\"Avg. committed\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.non_heap.committed\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}}},\"customLabel\":true},\"7d04d69b-99a3-462c-b4fd-0b51bd50a508\":{\"label\":\"Avg. used\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.non_heap.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}}},\"customLabel\":true}},\"columnOrder\":[\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\",\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\",\"7d04d69b-99a3-462c-b4fd-0b51bd50a508\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Non-heap memory usage\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":40,\"w\":24,\"h\":15,\"i\":\"ca9786a7-abfe-452c-9c89-ab331870ca68\"},\"panelIndex\":\"ca9786a7-abfe-452c-9c89-ab331870ca68\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-7f101489-db13-43e3-a1cd-fc0e9117361a\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\",\"maxLines\":1,\"showSingleSeries\":true,\"shouldTruncate\":true,\"isInside\":false},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"yTitle\":\"Usage [%]\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"area\",\"layers\":[{\"layerId\":\"7f101489-db13-43e3-a1cd-fc0e9117361a\",\"accessors\":[\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\"],\"position\":\"top\",\"seriesType\":\"line\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\",\"splitAccessor\":\"40532e8d-8c6f-4e08-a07f-4fd9a058d5cf\"}]},\"query\":{\"query\":\"jvm.memory.heap.pool.used :*\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"7f101489-db13-43e3-a1cd-fc0e9117361a\":{\"columns\":{\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX0\":{\"label\":\"Part of Avg. usage\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX1\":{\"label\":\"Part of Avg. usage\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.max\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX2\":{\"label\":\"Part of Avg. usage\",\"dataType\":\"number\",\"operationType\":\"math\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"tinymathAst\":{\"type\":\"function\",\"name\":\"divide\",\"args\":[\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX0\",\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX1\"],\"location\":{\"min\":0,\"max\":68},\"text\":\"average(jvm.memory.heap.pool.used)/average(jvm.memory.heap.pool.max)\"}},\"references\":[\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX0\",\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX1\"],\"customLabel\":true},\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\":{\"label\":\"Avg. usage\",\"dataType\":\"number\",\"operationType\":\"formula\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"formula\":\"average(jvm.memory.heap.pool.used)/average(jvm.memory.heap.pool.max)\",\"isFormulaBroken\":false,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"references\":[\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX2\"],\"customLabel\":true},\"40532e8d-8c6f-4e08-a07f-4fd9a058d5cf\":{\"label\":\"Top 3 values of labels.name\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"labels.name\",\"isBucketed\":true,\"params\":{\"size\":3,\"orderBy\":{\"type\":\"alphabetical\",\"fallback\":true},\"orderDirection\":\"asc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false}}},\"columnOrder\":[\"40532e8d-8c6f-4e08-a07f-4fd9a058d5cf\",\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\",\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\",\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX0\",\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX1\",\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX2\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Heap memory usage by pool\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":40,\"w\":24,\"h\":15,\"i\":\"4d8c0963-10dc-4ade-bb61-cbce3965daa5\"},\"panelIndex\":\"4d8c0963-10dc-4ade-bb61-cbce3965daa5\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsDatatable\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-c250b2e7-1fbf-4b7b-9f85-ddfd0edeb332\"}],\"state\":{\"visualization\":{\"columns\":[{\"isTransposed\":false,\"columnId\":\"4bee55ff-0735-4106-8e03-c68b714c86bd\"},{\"isTransposed\":false,\"columnId\":\"6630a2e5-966f-42e9-9621-60dfc2b7acfd\",\"colorMode\":\"none\"},{\"columnId\":\"0e3b242f-bb52-44fd-bb92-41cc1d0b9e06\",\"isTransposed\":false},{\"columnId\":\"31a2ee0a-02ec-46e9-877a-0e86e2c09abb\",\"isTransposed\":false,\"colorMode\":\"none\"},{\"columnId\":\"8c139e35-5893-41aa-a82d-f1c9e16fac1b\",\"isTransposed\":false,\"colorMode\":\"text\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":5,\"stops\":[{\"color\":\"#209280\",\"stop\":0.5},{\"color\":\"#54b399\",\"stop\":0.6},{\"color\":\"#d6bf57\",\"stop\":0.7},{\"color\":\"#e7664c\",\"stop\":0.8},{\"color\":\"#cc5642\",\"stop\":1.8}],\"name\":\"custom\",\"colorStops\":[{\"color\":\"#209280\",\"stop\":0},{\"color\":\"#54b399\",\"stop\":0.5},{\"color\":\"#d6bf57\",\"stop\":0.6},{\"color\":\"#e7664c\",\"stop\":0.7},{\"color\":\"#cc5642\",\"stop\":0.8}],\"continuity\":\"above\",\"reverse\":false,\"rangeMin\":0,\"rangeMax\":null,\"rangeType\":\"number\"}}}],\"layerId\":\"c250b2e7-1fbf-4b7b-9f85-ddfd0edeb332\",\"layerType\":\"data\"},\"query\":{\"query\":\"jvm.memory.heap.pool.used :*\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"c250b2e7-1fbf-4b7b-9f85-ddfd0edeb332\":{\"columns\":{\"4bee55ff-0735-4106-8e03-c68b714c86bd\":{\"label\":\"Memory pool\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"labels.name\",\"isBucketed\":true,\"params\":{\"size\":5,\"orderBy\":{\"type\":\"column\",\"columnId\":\"6630a2e5-966f-42e9-9621-60dfc2b7acfd\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false},\"customLabel\":true},\"6630a2e5-966f-42e9-9621-60dfc2b7acfd\":{\"label\":\"Committed [bytes]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.committed\",\"isBucketed\":false,\"scale\":\"ratio\",\"reducedTimeRange\":\"5m\",\"params\":{\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}},\"emptyAsNull\":true},\"customLabel\":true},\"0e3b242f-bb52-44fd-bb92-41cc1d0b9e06\":{\"label\":\"Limit [bytes]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.max\",\"isBucketed\":false,\"scale\":\"ratio\",\"reducedTimeRange\":\"5m\",\"params\":{\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}},\"emptyAsNull\":true},\"customLabel\":true},\"31a2ee0a-02ec-46e9-877a-0e86e2c09abb\":{\"label\":\"Used [bytes]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"reducedTimeRange\":\"5m\",\"params\":{\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}},\"emptyAsNull\":true},\"customLabel\":true},\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX0\":{\"label\":\"Part of Used [%]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"filter\":{\"query\":\"jvm.memory.heap.pool.used: *\",\"language\":\"kuery\"},\"reducedTimeRange\":\"5m\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX1\":{\"label\":\"Part of Used [%]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.max\",\"isBucketed\":false,\"scale\":\"ratio\",\"filter\":{\"query\":\"jvm.memory.heap.pool.max: *\",\"language\":\"kuery\"},\"reducedTimeRange\":\"5m\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX2\":{\"label\":\"Part of Used [%]\",\"dataType\":\"number\",\"operationType\":\"math\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"tinymathAst\":{\"type\":\"function\",\"name\":\"divide\",\"args\":[\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX0\",\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX1\"],\"location\":{\"min\":0,\"max\":139},\"text\":\"average(jvm.memory.heap.pool.used, kql='jvm.memory.heap.pool.used: *')/average(jvm.memory.heap.pool.max, kql='jvm.memory.heap.pool.max: *')\"}},\"references\":[\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX0\",\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX1\"],\"customLabel\":true},\"8c139e35-5893-41aa-a82d-f1c9e16fac1b\":{\"label\":\"Used [%]\",\"dataType\":\"number\",\"operationType\":\"formula\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"formula\":\"average(jvm.memory.heap.pool.used, kql='jvm.memory.heap.pool.used: *')/average(jvm.memory.heap.pool.max, kql='jvm.memory.heap.pool.max: *')\",\"isFormulaBroken\":false,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"references\":[\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX2\"],\"reducedTimeRange\":\"5m\",\"customLabel\":true}},\"columnOrder\":[\"4bee55ff-0735-4106-8e03-c68b714c86bd\",\"0e3b242f-bb52-44fd-bb92-41cc1d0b9e06\",\"6630a2e5-966f-42e9-9621-60dfc2b7acfd\",\"31a2ee0a-02ec-46e9-877a-0e86e2c09abb\",\"8c139e35-5893-41aa-a82d-f1c9e16fac1b\",\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX0\",\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX1\",\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX2\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Heap memory pools\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":55,\"w\":24,\"h\":15,\"i\":\"75bf2224-805f-46a1-9ba6-9ceb1d59258d\"},\"panelIndex\":\"75bf2224-805f-46a1-9ba6-9ceb1d59258d\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\",\"accessors\":[\"7bf46237-c31f-4b20-9f35-404b6b580f34\"],\"position\":\"top\",\"seriesType\":\"bar_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"60035d22-9253-4968-907b-9aa3a92d989a\",\"splitAccessor\":\"1e4f1019-33a4-4333-b1ef-163695a70cf3\"}],\"yLeftExtent\":{\"mode\":\"full\"},\"yTitle\":\"GC rate [count per minute]\"},\"query\":{\"query\":\"jvm.gc.count : *\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\":{\"columns\":{\"60035d22-9253-4968-907b-9aa3a92d989a\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"7bf46237-c31f-4b20-9f35-404b6b580f34\":{\"label\":\"Counter rate of jvm.gc.count per minute\",\"dataType\":\"number\",\"operationType\":\"counter_rate\",\"isBucketed\":false,\"scale\":\"ratio\",\"references\":[\"2cccccbc-e467-4be8-bbd4-0563bd1dd785\"],\"timeScale\":\"m\"},\"2cccccbc-e467-4be8-bbd4-0563bd1dd785\":{\"label\":\"Maximum of jvm.gc.count\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"jvm.gc.count\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true}},\"1e4f1019-33a4-4333-b1ef-163695a70cf3\":{\"label\":\"Top 3 values of labels.name\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"labels.name\",\"isBucketed\":true,\"params\":{\"size\":3,\"orderBy\":{\"type\":\"alphabetical\",\"fallback\":true},\"orderDirection\":\"asc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false}}},\"columnOrder\":[\"1e4f1019-33a4-4333-b1ef-163695a70cf3\",\"60035d22-9253-4968-907b-9aa3a92d989a\",\"7bf46237-c31f-4b20-9f35-404b6b580f34\",\"2cccccbc-e467-4be8-bbd4-0563bd1dd785\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Garbage collection count per minute\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":55,\"w\":24,\"h\":15,\"i\":\"1ed0da52-1b8b-49fb-b628-e8f785fe6807\"},\"panelIndex\":\"1ed0da52-1b8b-49fb-b628-e8f785fe6807\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\",\"accessors\":[\"7bf46237-c31f-4b20-9f35-404b6b580f34\"],\"position\":\"top\",\"seriesType\":\"bar_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"60035d22-9253-4968-907b-9aa3a92d989a\",\"splitAccessor\":\"1e4f1019-33a4-4333-b1ef-163695a70cf3\"}],\"yLeftExtent\":{\"mode\":\"full\"},\"yTitle\":\"GC time [ms per minute]\"},\"query\":{\"query\":\"jvm.gc.count : *\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\":{\"columns\":{\"60035d22-9253-4968-907b-9aa3a92d989a\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"7bf46237-c31f-4b20-9f35-404b6b580f34\":{\"label\":\"Counter rate of jvm.gc.time per minute\",\"dataType\":\"number\",\"operationType\":\"counter_rate\",\"isBucketed\":false,\"scale\":\"ratio\",\"references\":[\"ca05aa0b-f5de-4157-b24e-e8f6d77f20c5\"],\"timeScale\":\"m\",\"params\":{\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0}}}},\"1e4f1019-33a4-4333-b1ef-163695a70cf3\":{\"label\":\"Top 3 values of labels.name\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"labels.name\",\"isBucketed\":true,\"params\":{\"size\":3,\"orderBy\":{\"type\":\"alphabetical\",\"fallback\":true},\"orderDirection\":\"asc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false}},\"ca05aa0b-f5de-4157-b24e-e8f6d77f20c5\":{\"label\":\"Maximum of jvm.gc.time\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"jvm.gc.time\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true}}},\"columnOrder\":[\"1e4f1019-33a4-4333-b1ef-163695a70cf3\",\"60035d22-9253-4968-907b-9aa3a92d989a\",\"7bf46237-c31f-4b20-9f35-404b6b580f34\",\"ca05aa0b-f5de-4157-b24e-e8f6d77f20c5\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Garbage collection time spent per minute\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":70,\"w\":24,\"h\":15,\"i\":\"8a95eb8b-2507-42a9-b069-88a7c274a942\"},\"panelIndex\":\"8a95eb8b-2507-42a9-b069-88a7c274a942\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\",\"accessors\":[\"7bf46237-c31f-4b20-9f35-404b6b580f34\"],\"position\":\"top\",\"seriesType\":\"bar_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"60035d22-9253-4968-907b-9aa3a92d989a\"}],\"yLeftExtent\":{\"mode\":\"full\"},\"yTitle\":\"Memory allocation [bytes per minute]\"},\"query\":{\"query\":\"jvm.gc.alloc : *\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\":{\"columns\":{\"60035d22-9253-4968-907b-9aa3a92d989a\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"7bf46237-c31f-4b20-9f35-404b6b580f34\":{\"label\":\"Counter rate of jvm.gc.alloc per minute\",\"dataType\":\"number\",\"operationType\":\"counter_rate\",\"isBucketed\":false,\"scale\":\"ratio\",\"references\":[\"edb5bdc4-70ad-48fd-bd6b-4e68a9214636\"],\"timeScale\":\"m\",\"params\":{\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":0}}}},\"edb5bdc4-70ad-48fd-bd6b-4e68a9214636\":{\"label\":\"Maximum of jvm.gc.alloc\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"jvm.gc.alloc\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true}}},\"columnOrder\":[\"60035d22-9253-4968-907b-9aa3a92d989a\",\"7bf46237-c31f-4b20-9f35-404b6b580f34\",\"edb5bdc4-70ad-48fd-bd6b-4e68a9214636\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Memory allocation\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":70,\"w\":24,\"h\":15,\"i\":\"042cf2ef-9cd4-458c-87be-e6ac2c9d6d7e\"},\"panelIndex\":\"042cf2ef-9cd4-458c-87be-e6ac2c9d6d7e\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-ba118f97-82fd-4867-ae97-a071c22c7360\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"line\",\"layers\":[{\"layerId\":\"ba118f97-82fd-4867-ae97-a071c22c7360\",\"accessors\":[\"adb88f79-f380-4a6a-9f90-91316ececf1f\",\"92bdf4ef-b458-4c05-b4a3-d65db50c0ecc\"],\"position\":\"top\",\"seriesType\":\"line\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"69640a9f-0f72-46d0-94b2-47930dc0272e\"}],\"yTitle\":\"Thread count\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"ba118f97-82fd-4867-ae97-a071c22c7360\":{\"columns\":{\"69640a9f-0f72-46d0-94b2-47930dc0272e\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"adb88f79-f380-4a6a-9f90-91316ececf1f\":{\"label\":\"Max\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"jvm.thread.count\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true},\"92bdf4ef-b458-4c05-b4a3-d65db50c0ecc\":{\"label\":\"Average\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.thread.count\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true}},\"columnOrder\":[\"69640a9f-0f72-46d0-94b2-47930dc0272e\",\"92bdf4ef-b458-4c05-b4a3-d65db50c0ecc\",\"adb88f79-f380-4a6a-9f90-91316ececf1f\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Thread count\"}]", + "panelsJSON": "[{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":0,\"w\":48,\"h\":10,\"i\":\"7b6cce32-fe3c-47a3-8784-6646ee4d5b24\"},\"panelIndex\":\"7b6cce32-fe3c-47a3-8784-6646ee4d5b24\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsDatatable\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-ffdfcd10-9cab-4806-813b-5c1c5053584e\"}],\"state\":{\"visualization\":{\"columns\":[{\"columnId\":\"03bdc1b7-9f72-4d24-89ae-72014a51a251\",\"isTransposed\":false,\"oneClickFilter\":false},{\"columnId\":\"51804f56-a2e5-44fd-bb44-762d7071437a\",\"isTransposed\":false,\"colorMode\":\"text\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":5,\"stops\":[{\"color\":\"#209280\",\"stop\":0.5},{\"color\":\"#54b399\",\"stop\":0.7},{\"color\":\"#d6bf57\",\"stop\":0.8},{\"color\":\"#e7664c\",\"stop\":0.9},{\"color\":\"#cc5642\",\"stop\":1.9}],\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"name\":\"custom\",\"colorStops\":[{\"color\":\"#209280\",\"stop\":0},{\"color\":\"#54b399\",\"stop\":0.5},{\"color\":\"#d6bf57\",\"stop\":0.7},{\"color\":\"#e7664c\",\"stop\":0.8},{\"color\":\"#cc5642\",\"stop\":0.9}],\"continuity\":\"above\",\"reverse\":false}}},{\"columnId\":\"bc1e385f-8a20-4227-980c-ee1f462e9c5b\",\"isTransposed\":false},{\"columnId\":\"fc9f178f-1bf3-4ec9-b709-2cf563038d8b\",\"isTransposed\":false},{\"columnId\":\"fd3d4405-64dd-4bdd-b5a6-79a89e9d7730\",\"isTransposed\":false},{\"columnId\":\"8bf5c093-6115-4f73-a279-1dd576647e20\",\"isTransposed\":false},{\"columnId\":\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7d\",\"isTransposed\":false,\"colorMode\":\"text\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":5,\"stops\":[{\"color\":\"#209280\",\"stop\":0.6},{\"color\":\"#54b399\",\"stop\":0.7},{\"color\":\"#d6bf57\",\"stop\":0.8},{\"color\":\"#e7664c\",\"stop\":0.9},{\"color\":\"#cc5642\",\"stop\":1.9}],\"name\":\"custom\",\"colorStops\":[{\"color\":\"#209280\",\"stop\":0},{\"color\":\"#54b399\",\"stop\":0.6},{\"color\":\"#d6bf57\",\"stop\":0.7},{\"color\":\"#e7664c\",\"stop\":0.8},{\"color\":\"#cc5642\",\"stop\":0.9}],\"continuity\":\"above\",\"reverse\":false,\"rangeMin\":0,\"rangeMax\":null,\"rangeType\":\"number\"}}}],\"layerId\":\"ffdfcd10-9cab-4806-813b-5c1c5053584e\",\"layerType\":\"data\"},\"query\":{\"query\":\"agent.name: java\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"ffdfcd10-9cab-4806-813b-5c1c5053584e\":{\"columns\":{\"03bdc1b7-9f72-4d24-89ae-72014a51a251\":{\"label\":\"JVM (Top 10)\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"service.node.name\",\"isBucketed\":true,\"params\":{\"size\":10,\"orderBy\":{\"type\":\"column\",\"columnId\":\"51804f56-a2e5-44fd-bb44-762d7071437a\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false},\"customLabel\":true},\"51804f56-a2e5-44fd-bb44-762d7071437a\":{\"label\":\"CPU avg\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"system.cpu.total.norm.pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":1,\"compact\":false}}},\"customLabel\":true},\"bc1e385f-8a20-4227-980c-ee1f462e9c5b\":{\"label\":\"Heap memory avg\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":1}}},\"customLabel\":true},\"fc9f178f-1bf3-4ec9-b709-2cf563038d8b\":{\"label\":\"Non-heap memory avg\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.non_heap.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":1}}},\"customLabel\":true},\"fd3d4405-64dd-4bdd-b5a6-79a89e9d7730\":{\"label\":\"Thread count max\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"jvm.thread.count\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0}}},\"customLabel\":true},\"8bf5c093-6115-4f73-a279-1dd576647e20\":{\"label\":\"Host name\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"host.name\",\"isBucketed\":true,\"params\":{\"size\":1,\"orderBy\":{\"type\":\"column\",\"columnId\":\"51804f56-a2e5-44fd-bb44-762d7071437a\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false},\"customLabel\":true},\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX0\":{\"label\":\"Part of Heap avg [%]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX1\":{\"label\":\"Part of Heap avg [%]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.max\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX2\":{\"label\":\"Part of Heap avg [%]\",\"dataType\":\"number\",\"operationType\":\"math\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"tinymathAst\":{\"type\":\"function\",\"name\":\"divide\",\"args\":[\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX0\",\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX1\"],\"location\":{\"min\":0,\"max\":58},\"text\":\"average(jvm.memory.heap.used)/average(jvm.memory.heap.max)\"}},\"references\":[\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX0\",\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX1\"],\"customLabel\":true},\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7d\":{\"label\":\"Heap usage avg [%]\",\"dataType\":\"number\",\"operationType\":\"formula\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"formula\":\"average(jvm.memory.heap.used)/average(jvm.memory.heap.max)\",\"isFormulaBroken\":false,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":1}}},\"references\":[\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX2\"],\"customLabel\":true}},\"columnOrder\":[\"03bdc1b7-9f72-4d24-89ae-72014a51a251\",\"8bf5c093-6115-4f73-a279-1dd576647e20\",\"51804f56-a2e5-44fd-bb44-762d7071437a\",\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7d\",\"bc1e385f-8a20-4227-980c-ee1f462e9c5b\",\"fc9f178f-1bf3-4ec9-b709-2cf563038d8b\",\"fd3d4405-64dd-4bdd-b5a6-79a89e9d7730\",\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX0\",\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX1\",\"b39b043b-9abc-4a0e-b15c-f82e84f0fb7dX2\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{}}},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":10,\"w\":24,\"h\":15,\"i\":\"e0987960-239c-4bc4-85af-6d25e3f63607\"},\"panelIndex\":\"e0987960-239c-4bc4-85af-6d25e3f63607\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-f29b4866-f576-49a4-af42-efafad81d0ff\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"line\",\"layers\":[{\"layerId\":\"f29b4866-f576-49a4-af42-efafad81d0ff\",\"accessors\":[\"2cb44b2f-fff3-45e4-b40e-e067daf21b52\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767\",\"3ac12c4e-f2c9-4914-b461-1ec3e96ac6e7\",\"28a6e0b4-1f21-4b22-b006-aa2d8ff69b27\"],\"position\":\"top\",\"seriesType\":\"line\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"fd579e72-9688-4cc3-987a-814c255ef7a4\",\"yConfig\":[{\"forAccessor\":\"3ac12c4e-f2c9-4914-b461-1ec3e96ac6e7\",\"color\":\"#d6bf57\"},{\"forAccessor\":\"28a6e0b4-1f21-4b22-b006-aa2d8ff69b27\",\"color\":\"#da8b45\"}]}],\"yTitle\":\"Utilization [%]\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"f29b4866-f576-49a4-af42-efafad81d0ff\":{\"columns\":{\"fd579e72-9688-4cc3-987a-814c255ef7a4\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"2cb44b2f-fff3-45e4-b40e-e067daf21b52\":{\"label\":\"System average\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"system.cpu.total.norm.pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"customLabel\":true},\"2d12ce33-9691-4f4a-9717-eab6e4fed767\":{\"label\":\"System max\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"system.cpu.total.norm.pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"customLabel\":true},\"3ac12c4e-f2c9-4914-b461-1ec3e96ac6e7\":{\"label\":\"Process average\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"system.process.cpu.total.norm.pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"customLabel\":true},\"28a6e0b4-1f21-4b22-b006-aa2d8ff69b27\":{\"label\":\"Process max\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"system.process.cpu.total.norm.pct\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2,\"compact\":false}}},\"customLabel\":true}},\"columnOrder\":[\"fd579e72-9688-4cc3-987a-814c255ef7a4\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767\",\"3ac12c4e-f2c9-4914-b461-1ec3e96ac6e7\",\"28a6e0b4-1f21-4b22-b006-aa2d8ff69b27\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"CPU Usage\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":10,\"w\":24,\"h\":15,\"i\":\"02a5f484-9647-4559-8706-4b3f63b3f5e8\"},\"panelIndex\":\"02a5f484-9647-4559-8706-4b3f63b3f5e8\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-f29b4866-f576-49a4-af42-efafad81d0ff\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"line\",\"layers\":[{\"layerId\":\"f29b4866-f576-49a4-af42-efafad81d0ff\",\"accessors\":[\"2cb44b2f-fff3-45e4-b40e-e067daf21b52\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767\"],\"position\":\"top\",\"seriesType\":\"line\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"fd579e72-9688-4cc3-987a-814c255ef7a4\",\"yConfig\":[]}],\"yTitle\":\"Usage [%]\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"f29b4866-f576-49a4-af42-efafad81d0ff\":{\"columns\":{\"fd579e72-9688-4cc3-987a-814c255ef7a4\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X0\":{\"label\":\"Part of System average\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"system.memory.actual.free\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X1\":{\"label\":\"Part of System average\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"system.memory.total\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X2\":{\"label\":\"Part of System average\",\"dataType\":\"number\",\"operationType\":\"math\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"tinymathAst\":{\"type\":\"function\",\"name\":\"subtract\",\"args\":[1,{\"type\":\"function\",\"name\":\"divide\",\"args\":[\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X0\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X1\"],\"location\":{\"min\":3,\"max\":67},\"text\":\" average(system.memory.actual.free)/average(system.memory.total)\"}],\"location\":{\"min\":0,\"max\":67},\"text\":\"1 - average(system.memory.actual.free)/average(system.memory.total)\"}},\"references\":[\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X0\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X1\"],\"customLabel\":true},\"2cb44b2f-fff3-45e4-b40e-e067daf21b52\":{\"label\":\"Average\",\"dataType\":\"number\",\"operationType\":\"formula\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"formula\":\"1 - average(system.memory.actual.free)/average(system.memory.total)\",\"isFormulaBroken\":false,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"references\":[\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X2\"],\"customLabel\":true},\"2d12ce33-9691-4f4a-9717-eab6e4fed767X0\":{\"label\":\"Part of Max\",\"dataType\":\"number\",\"operationType\":\"min\",\"sourceField\":\"system.memory.actual.free\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"2d12ce33-9691-4f4a-9717-eab6e4fed767X1\":{\"label\":\"Part of Max\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"system.memory.total\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"2d12ce33-9691-4f4a-9717-eab6e4fed767X2\":{\"label\":\"Part of Max\",\"dataType\":\"number\",\"operationType\":\"math\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"tinymathAst\":{\"type\":\"function\",\"name\":\"subtract\",\"args\":[1,{\"type\":\"function\",\"name\":\"divide\",\"args\":[\"2d12ce33-9691-4f4a-9717-eab6e4fed767X0\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767X1\"],\"location\":{\"min\":3,\"max\":59},\"text\":\" min(system.memory.actual.free)/max(system.memory.total)\"}],\"location\":{\"min\":0,\"max\":59},\"text\":\"1 - min(system.memory.actual.free)/max(system.memory.total)\"}},\"references\":[\"2d12ce33-9691-4f4a-9717-eab6e4fed767X0\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767X1\"],\"customLabel\":true},\"2d12ce33-9691-4f4a-9717-eab6e4fed767\":{\"label\":\"Max\",\"dataType\":\"number\",\"operationType\":\"formula\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"formula\":\"1 - min(system.memory.actual.free)/max(system.memory.total)\",\"isFormulaBroken\":false,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"references\":[\"2d12ce33-9691-4f4a-9717-eab6e4fed767X2\"],\"customLabel\":true}},\"columnOrder\":[\"fd579e72-9688-4cc3-987a-814c255ef7a4\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X0\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X1\",\"2cb44b2f-fff3-45e4-b40e-e067daf21b52X2\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767X0\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767X1\",\"2d12ce33-9691-4f4a-9717-eab6e4fed767X2\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"System Memory Usage\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":25,\"w\":24,\"h\":15,\"i\":\"5e044c2f-a316-4180-8f21-571fec481377\"},\"panelIndex\":\"5e044c2f-a316-4180-8f21-571fec481377\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-7f101489-db13-43e3-a1cd-fc0e9117361a\"},{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-2df2bccd-257b-4ec4-ba84-b022128ff511\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\",\"maxLines\":1,\"showSingleSeries\":true,\"shouldTruncate\":true,\"isInside\":false},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"yTitle\":\"Usage [bytes]\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"area\",\"layers\":[{\"layerId\":\"7f101489-db13-43e3-a1cd-fc0e9117361a\",\"accessors\":[\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\",\"7d04d69b-99a3-462c-b4fd-0b51bd50a508\"],\"position\":\"top\",\"seriesType\":\"area\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\"},{\"layerId\":\"2df2bccd-257b-4ec4-ba84-b022128ff511\",\"layerType\":\"data\",\"accessors\":[\"8cbe1326-c46a-437b-ad96-5fb9feefa997\"],\"seriesType\":\"line\",\"xAccessor\":\"51a76fb0-bc4e-4c0c-aa43-38b96b8778a0\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"7f101489-db13-43e3-a1cd-fc0e9117361a\":{\"columns\":{\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\":{\"label\":\"Avg. committed\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.committed\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}}},\"customLabel\":true},\"7d04d69b-99a3-462c-b4fd-0b51bd50a508\":{\"label\":\"Avg. used\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}}},\"customLabel\":true}},\"columnOrder\":[\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\",\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\",\"7d04d69b-99a3-462c-b4fd-0b51bd50a508\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}},\"2df2bccd-257b-4ec4-ba84-b022128ff511\":{\"linkToLayers\":[],\"columns\":{\"51a76fb0-bc4e-4c0c-aa43-38b96b8778a0\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"8cbe1326-c46a-437b-ad96-5fb9feefa997\":{\"label\":\"Limit\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.max\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}}},\"customLabel\":true}},\"columnOrder\":[\"51a76fb0-bc4e-4c0c-aa43-38b96b8778a0\",\"8cbe1326-c46a-437b-ad96-5fb9feefa997\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Heap memory usage\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":25,\"w\":24,\"h\":15,\"i\":\"5dd8b3f8-67f4-41d3-84f2-37d20d0f4020\"},\"panelIndex\":\"5dd8b3f8-67f4-41d3-84f2-37d20d0f4020\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-7f101489-db13-43e3-a1cd-fc0e9117361a\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\",\"maxLines\":1,\"showSingleSeries\":true,\"shouldTruncate\":true,\"isInside\":false},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"yTitle\":\"Usage [bytes]\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"area\",\"layers\":[{\"layerId\":\"7f101489-db13-43e3-a1cd-fc0e9117361a\",\"accessors\":[\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\",\"7d04d69b-99a3-462c-b4fd-0b51bd50a508\"],\"position\":\"top\",\"seriesType\":\"area\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\"}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"7f101489-db13-43e3-a1cd-fc0e9117361a\":{\"columns\":{\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\":{\"label\":\"Avg. committed\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.non_heap.committed\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}}},\"customLabel\":true},\"7d04d69b-99a3-462c-b4fd-0b51bd50a508\":{\"label\":\"Avg. used\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.non_heap.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true,\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}}},\"customLabel\":true}},\"columnOrder\":[\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\",\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\",\"7d04d69b-99a3-462c-b4fd-0b51bd50a508\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Non-heap memory usage\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":40,\"w\":24,\"h\":15,\"i\":\"ca9786a7-abfe-452c-9c89-ab331870ca68\"},\"panelIndex\":\"ca9786a7-abfe-452c-9c89-ab331870ca68\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-7f101489-db13-43e3-a1cd-fc0e9117361a\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\",\"maxLines\":1,\"showSingleSeries\":true,\"shouldTruncate\":true,\"isInside\":false},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"yTitle\":\"Usage [%]\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"area\",\"layers\":[{\"layerId\":\"7f101489-db13-43e3-a1cd-fc0e9117361a\",\"accessors\":[\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\"],\"position\":\"top\",\"seriesType\":\"line\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\",\"splitAccessor\":\"40532e8d-8c6f-4e08-a07f-4fd9a058d5cf\"}]},\"query\":{\"query\":\"jvm.memory.heap.pool.used :*\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"7f101489-db13-43e3-a1cd-fc0e9117361a\":{\"columns\":{\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX0\":{\"label\":\"Part of Avg. usage\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX1\":{\"label\":\"Part of Avg. usage\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.max\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX2\":{\"label\":\"Part of Avg. usage\",\"dataType\":\"number\",\"operationType\":\"math\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"tinymathAst\":{\"type\":\"function\",\"name\":\"divide\",\"args\":[\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX0\",\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX1\"],\"location\":{\"min\":0,\"max\":68},\"text\":\"average(jvm.memory.heap.pool.used)/average(jvm.memory.heap.pool.max)\"}},\"references\":[\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX0\",\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX1\"],\"customLabel\":true},\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\":{\"label\":\"Avg. usage\",\"dataType\":\"number\",\"operationType\":\"formula\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"formula\":\"average(jvm.memory.heap.pool.used)/average(jvm.memory.heap.pool.max)\",\"isFormulaBroken\":false,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"references\":[\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX2\"],\"customLabel\":true},\"40532e8d-8c6f-4e08-a07f-4fd9a058d5cf\":{\"label\":\"Top 3 values of labels.name\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"labels.name\",\"isBucketed\":true,\"params\":{\"size\":3,\"orderBy\":{\"type\":\"alphabetical\",\"fallback\":true},\"orderDirection\":\"asc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false}}},\"columnOrder\":[\"40532e8d-8c6f-4e08-a07f-4fd9a058d5cf\",\"ef5df4a6-4c75-41f2-8aca-c15b4bcf394c\",\"009fb3d0-5ef3-450e-822c-ab6d936c50eb\",\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX0\",\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX1\",\"009fb3d0-5ef3-450e-822c-ab6d936c50ebX2\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Heap memory usage by pool\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":40,\"w\":24,\"h\":15,\"i\":\"4d8c0963-10dc-4ade-bb61-cbce3965daa5\"},\"panelIndex\":\"4d8c0963-10dc-4ade-bb61-cbce3965daa5\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsDatatable\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-c250b2e7-1fbf-4b7b-9f85-ddfd0edeb332\"}],\"state\":{\"visualization\":{\"columns\":[{\"isTransposed\":false,\"columnId\":\"4bee55ff-0735-4106-8e03-c68b714c86bd\"},{\"isTransposed\":false,\"columnId\":\"6630a2e5-966f-42e9-9621-60dfc2b7acfd\",\"colorMode\":\"none\"},{\"columnId\":\"0e3b242f-bb52-44fd-bb92-41cc1d0b9e06\",\"isTransposed\":false},{\"columnId\":\"31a2ee0a-02ec-46e9-877a-0e86e2c09abb\",\"isTransposed\":false,\"colorMode\":\"none\"},{\"columnId\":\"8c139e35-5893-41aa-a82d-f1c9e16fac1b\",\"isTransposed\":false,\"colorMode\":\"text\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":5,\"stops\":[{\"color\":\"#209280\",\"stop\":0.5},{\"color\":\"#54b399\",\"stop\":0.6},{\"color\":\"#d6bf57\",\"stop\":0.7},{\"color\":\"#e7664c\",\"stop\":0.8},{\"color\":\"#cc5642\",\"stop\":1.8}],\"name\":\"custom\",\"colorStops\":[{\"color\":\"#209280\",\"stop\":0},{\"color\":\"#54b399\",\"stop\":0.5},{\"color\":\"#d6bf57\",\"stop\":0.6},{\"color\":\"#e7664c\",\"stop\":0.7},{\"color\":\"#cc5642\",\"stop\":0.8}],\"continuity\":\"above\",\"reverse\":false,\"rangeMin\":0,\"rangeMax\":null,\"rangeType\":\"number\"}}}],\"layerId\":\"c250b2e7-1fbf-4b7b-9f85-ddfd0edeb332\",\"layerType\":\"data\"},\"query\":{\"query\":\"jvm.memory.heap.pool.used :*\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"c250b2e7-1fbf-4b7b-9f85-ddfd0edeb332\":{\"columns\":{\"4bee55ff-0735-4106-8e03-c68b714c86bd\":{\"label\":\"Memory pool\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"labels.name\",\"isBucketed\":true,\"params\":{\"size\":5,\"orderBy\":{\"type\":\"column\",\"columnId\":\"6630a2e5-966f-42e9-9621-60dfc2b7acfd\"},\"orderDirection\":\"desc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false},\"customLabel\":true},\"6630a2e5-966f-42e9-9621-60dfc2b7acfd\":{\"label\":\"Committed [bytes]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.committed\",\"isBucketed\":false,\"scale\":\"ratio\",\"reducedTimeRange\":\"5m\",\"params\":{\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}},\"emptyAsNull\":true},\"customLabel\":true},\"0e3b242f-bb52-44fd-bb92-41cc1d0b9e06\":{\"label\":\"Limit [bytes]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.max\",\"isBucketed\":false,\"scale\":\"ratio\",\"reducedTimeRange\":\"5m\",\"params\":{\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}},\"emptyAsNull\":true},\"customLabel\":true},\"31a2ee0a-02ec-46e9-877a-0e86e2c09abb\":{\"label\":\"Used [bytes]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"reducedTimeRange\":\"5m\",\"params\":{\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":2}},\"emptyAsNull\":true},\"customLabel\":true},\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX0\":{\"label\":\"Part of Used [%]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.used\",\"isBucketed\":false,\"scale\":\"ratio\",\"filter\":{\"query\":\"jvm.memory.heap.pool.used: *\",\"language\":\"kuery\"},\"reducedTimeRange\":\"5m\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX1\":{\"label\":\"Part of Used [%]\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.memory.heap.pool.max\",\"isBucketed\":false,\"scale\":\"ratio\",\"filter\":{\"query\":\"jvm.memory.heap.pool.max: *\",\"language\":\"kuery\"},\"reducedTimeRange\":\"5m\",\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX2\":{\"label\":\"Part of Used [%]\",\"dataType\":\"number\",\"operationType\":\"math\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"tinymathAst\":{\"type\":\"function\",\"name\":\"divide\",\"args\":[\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX0\",\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX1\"],\"location\":{\"min\":0,\"max\":139},\"text\":\"average(jvm.memory.heap.pool.used, kql='jvm.memory.heap.pool.used: *')/average(jvm.memory.heap.pool.max, kql='jvm.memory.heap.pool.max: *')\"}},\"references\":[\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX0\",\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX1\"],\"customLabel\":true},\"8c139e35-5893-41aa-a82d-f1c9e16fac1b\":{\"label\":\"Used [%]\",\"dataType\":\"number\",\"operationType\":\"formula\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"formula\":\"average(jvm.memory.heap.pool.used, kql='jvm.memory.heap.pool.used: *')/average(jvm.memory.heap.pool.max, kql='jvm.memory.heap.pool.max: *')\",\"isFormulaBroken\":false,\"format\":{\"id\":\"percent\",\"params\":{\"decimals\":2}}},\"references\":[\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX2\"],\"reducedTimeRange\":\"5m\",\"customLabel\":true}},\"columnOrder\":[\"4bee55ff-0735-4106-8e03-c68b714c86bd\",\"0e3b242f-bb52-44fd-bb92-41cc1d0b9e06\",\"6630a2e5-966f-42e9-9621-60dfc2b7acfd\",\"31a2ee0a-02ec-46e9-877a-0e86e2c09abb\",\"8c139e35-5893-41aa-a82d-f1c9e16fac1b\",\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX0\",\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX1\",\"8c139e35-5893-41aa-a82d-f1c9e16fac1bX2\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Heap memory pools\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":55,\"w\":24,\"h\":15,\"i\":\"75bf2224-805f-46a1-9ba6-9ceb1d59258d\"},\"panelIndex\":\"75bf2224-805f-46a1-9ba6-9ceb1d59258d\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\",\"accessors\":[\"7bf46237-c31f-4b20-9f35-404b6b580f34\"],\"position\":\"top\",\"seriesType\":\"bar_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"60035d22-9253-4968-907b-9aa3a92d989a\",\"splitAccessor\":\"1e4f1019-33a4-4333-b1ef-163695a70cf3\"}],\"yLeftExtent\":{\"mode\":\"full\"},\"yTitle\":\"GC rate [count per minute]\"},\"query\":{\"query\":\"jvm.gc.count : *\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\":{\"columns\":{\"60035d22-9253-4968-907b-9aa3a92d989a\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"7bf46237-c31f-4b20-9f35-404b6b580f34\":{\"label\":\"Counter rate of jvm.gc.count per minute\",\"dataType\":\"number\",\"operationType\":\"counter_rate\",\"isBucketed\":false,\"scale\":\"ratio\",\"references\":[\"2cccccbc-e467-4be8-bbd4-0563bd1dd785\"],\"timeScale\":\"m\"},\"2cccccbc-e467-4be8-bbd4-0563bd1dd785\":{\"label\":\"Maximum of jvm.gc.count\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"jvm.gc.count\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true}},\"1e4f1019-33a4-4333-b1ef-163695a70cf3\":{\"label\":\"Top 3 values of labels.name\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"labels.name\",\"isBucketed\":true,\"params\":{\"size\":3,\"orderBy\":{\"type\":\"alphabetical\",\"fallback\":true},\"orderDirection\":\"asc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false}}},\"columnOrder\":[\"1e4f1019-33a4-4333-b1ef-163695a70cf3\",\"60035d22-9253-4968-907b-9aa3a92d989a\",\"7bf46237-c31f-4b20-9f35-404b6b580f34\",\"2cccccbc-e467-4be8-bbd4-0563bd1dd785\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Garbage collection count per minute\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":55,\"w\":24,\"h\":15,\"i\":\"1ed0da52-1b8b-49fb-b628-e8f785fe6807\"},\"panelIndex\":\"1ed0da52-1b8b-49fb-b628-e8f785fe6807\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\",\"accessors\":[\"7bf46237-c31f-4b20-9f35-404b6b580f34\"],\"position\":\"top\",\"seriesType\":\"bar_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"60035d22-9253-4968-907b-9aa3a92d989a\",\"splitAccessor\":\"1e4f1019-33a4-4333-b1ef-163695a70cf3\"}],\"yLeftExtent\":{\"mode\":\"full\"},\"yTitle\":\"GC time [ms per minute]\"},\"query\":{\"query\":\"jvm.gc.count : *\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\":{\"columns\":{\"60035d22-9253-4968-907b-9aa3a92d989a\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"7bf46237-c31f-4b20-9f35-404b6b580f34\":{\"label\":\"Counter rate of jvm.gc.time per minute\",\"dataType\":\"number\",\"operationType\":\"counter_rate\",\"isBucketed\":false,\"scale\":\"ratio\",\"references\":[\"ca05aa0b-f5de-4157-b24e-e8f6d77f20c5\"],\"timeScale\":\"m\",\"params\":{\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0}}}},\"1e4f1019-33a4-4333-b1ef-163695a70cf3\":{\"label\":\"Top 3 values of labels.name\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"labels.name\",\"isBucketed\":true,\"params\":{\"size\":3,\"orderBy\":{\"type\":\"alphabetical\",\"fallback\":true},\"orderDirection\":\"asc\",\"otherBucket\":true,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false}},\"ca05aa0b-f5de-4157-b24e-e8f6d77f20c5\":{\"label\":\"Maximum of jvm.gc.time\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"jvm.gc.time\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true}}},\"columnOrder\":[\"1e4f1019-33a4-4333-b1ef-163695a70cf3\",\"60035d22-9253-4968-907b-9aa3a92d989a\",\"7bf46237-c31f-4b20-9f35-404b6b580f34\",\"ca05aa0b-f5de-4157-b24e-e8f6d77f20c5\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Garbage collection time spent per minute\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":70,\"w\":24,\"h\":15,\"i\":\"8a95eb8b-2507-42a9-b069-88a7c274a942\"},\"panelIndex\":\"8a95eb8b-2507-42a9-b069-88a7c274a942\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"bar_stacked\",\"layers\":[{\"layerId\":\"0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\",\"accessors\":[\"7bf46237-c31f-4b20-9f35-404b6b580f34\"],\"position\":\"top\",\"seriesType\":\"bar_stacked\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"60035d22-9253-4968-907b-9aa3a92d989a\"}],\"yLeftExtent\":{\"mode\":\"full\"},\"yTitle\":\"Memory allocation [bytes per minute]\"},\"query\":{\"query\":\"jvm.gc.alloc : *\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"0a3b7d42-6be0-4d63-89b4-1ff4f845bb2b\":{\"columns\":{\"60035d22-9253-4968-907b-9aa3a92d989a\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"7bf46237-c31f-4b20-9f35-404b6b580f34\":{\"label\":\"Counter rate of jvm.gc.alloc per minute\",\"dataType\":\"number\",\"operationType\":\"counter_rate\",\"isBucketed\":false,\"scale\":\"ratio\",\"references\":[\"edb5bdc4-70ad-48fd-bd6b-4e68a9214636\"],\"timeScale\":\"m\",\"params\":{\"format\":{\"id\":\"bytes\",\"params\":{\"decimals\":0}}}},\"edb5bdc4-70ad-48fd-bd6b-4e68a9214636\":{\"label\":\"Maximum of jvm.gc.alloc\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"jvm.gc.alloc\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true}}},\"columnOrder\":[\"60035d22-9253-4968-907b-9aa3a92d989a\",\"7bf46237-c31f-4b20-9f35-404b6b580f34\",\"edb5bdc4-70ad-48fd-bd6b-4e68a9214636\"],\"incompleteColumns\":{},\"sampling\":1}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Memory allocation\"},{\"version\":\"8.10.0-SNAPSHOT\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":70,\"w\":24,\"h\":15,\"i\":\"042cf2ef-9cd4-458c-87be-e6ac2c9d6d7e\"},\"panelIndex\":\"042cf2ef-9cd4-458c-87be-e6ac2c9d6d7e\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"APM_STATIC_DATA_VIEW_ID\",\"name\":\"indexpattern-datasource-layer-ba118f97-82fd-4867-ae97-a071c22c7360\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":true,\"position\":\"bottom\"},\"valueLabels\":\"hide\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":true,\"yLeft\":true,\"yRight\":true},\"preferredSeriesType\":\"line\",\"layers\":[{\"layerId\":\"ba118f97-82fd-4867-ae97-a071c22c7360\",\"accessors\":[\"adb88f79-f380-4a6a-9f90-91316ececf1f\",\"92bdf4ef-b458-4c05-b4a3-d65db50c0ecc\"],\"position\":\"top\",\"seriesType\":\"line\",\"showGridlines\":false,\"layerType\":\"data\",\"xAccessor\":\"69640a9f-0f72-46d0-94b2-47930dc0272e\"}],\"yTitle\":\"Thread count\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"ba118f97-82fd-4867-ae97-a071c22c7360\":{\"columns\":{\"69640a9f-0f72-46d0-94b2-47930dc0272e\":{\"label\":\"@timestamp\",\"dataType\":\"date\",\"operationType\":\"date_histogram\",\"sourceField\":\"@timestamp\",\"isBucketed\":true,\"scale\":\"interval\",\"params\":{\"interval\":\"auto\",\"includeEmptyRows\":true,\"dropPartials\":false}},\"adb88f79-f380-4a6a-9f90-91316ececf1f\":{\"label\":\"Max\",\"dataType\":\"number\",\"operationType\":\"max\",\"sourceField\":\"jvm.thread.count\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true},\"92bdf4ef-b458-4c05-b4a3-d65db50c0ecc\":{\"label\":\"Average\",\"dataType\":\"number\",\"operationType\":\"average\",\"sourceField\":\"jvm.thread.count\",\"isBucketed\":false,\"scale\":\"ratio\",\"params\":{\"emptyAsNull\":true},\"customLabel\":true}},\"columnOrder\":[\"69640a9f-0f72-46d0-94b2-47930dc0272e\",\"92bdf4ef-b458-4c05-b4a3-d65db50c0ecc\",\"adb88f79-f380-4a6a-9f90-91316ececf1f\"],\"sampling\":1,\"ignoreGlobalFilters\":false,\"incompleteColumns\":{}}}},\"indexpattern\":{\"layers\":{}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Thread count\"}]", "timeRestore": false, "title": "JVM-Dashboard", "version": 1 @@ -91,4 +91,4 @@ "typeMigrationVersion": "8.9.0", "updated_at": "2023-07-25T08:13:29.621Z", "version": "WzYxMzczLDEyXQ==" -} \ No newline at end of file +} diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_dashboards/actions/save_dashboard_modal.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_dashboards/actions/save_dashboard_modal.tsx index 739fe2634289..5f2f91df4423 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_dashboards/actions/save_dashboard_modal.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_dashboards/actions/save_dashboard_modal.tsx @@ -23,7 +23,6 @@ import { EuiButtonEmpty, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { DashboardItem } from '@kbn/dashboard-plugin/common/content_management'; import { callApmApi } from '../../../../services/rest/create_call_apm_api'; import { useDashboardFetcher } from '../../../../hooks/use_dashboards_fetcher'; import { FETCH_STATUS } from '../../../../hooks/use_fetcher'; @@ -76,7 +75,7 @@ export function SaveDashboardModal({ const isEditMode = !!currentDashboard?.id; - const options = allAvailableDashboards?.map((dashboardItem: DashboardItem) => ({ + const options = allAvailableDashboards?.map((dashboardItem) => ({ label: dashboardItem.attributes.title, value: dashboardItem.id, disabled: diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/transaction_action_menu/__snapshots__/transaction_action_menu.test.tsx.snap b/x-pack/plugins/observability_solution/apm/public/components/shared/transaction_action_menu/__snapshots__/transaction_action_menu.test.tsx.snap index 023caad49948..63f0a9ff2f3c 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/transaction_action_menu/__snapshots__/transaction_action_menu.test.tsx.snap +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/transaction_action_menu/__snapshots__/transaction_action_menu.test.tsx.snap @@ -3,7 +3,7 @@ exports[`TransactionActionMenu matches the snapshot 1`] = `

    @@ -94,23 +100,7 @@ export function KnowledgeBaseEditManualEntryFlyout({
    - {!entry ? ( - - setNewEntryId(e.target.value)} - isInvalid={isEntryIdInvalid} - /> - - ) : ( + {entry ? ( @@ -136,7 +126,26 @@ export function KnowledgeBaseEditManualEntryFlyout({
    - )} + ) : null} + + + + + setNewEntryTitle(e.target.value)} + isInvalid={isEntryTitleInvalid} + /> + + 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 e8152738e380..1c05ca6d52b3 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 @@ -30,19 +30,19 @@ export function KnowledgeBaseEditUserInstructionFlyout({ onClose }: { onClose: ( const { userInstructions, isLoading: isFetching } = useGetUserInstructions(); const { mutateAsync: createEntry, isLoading: isSaving } = useCreateKnowledgeBaseUserInstruction(); const [newEntryText, setNewEntryText] = useState(''); - const [newEntryDocId, setNewEntryDocId] = useState(); + const [newEntryId, setNewEntryId] = useState(); const isSubmitDisabled = newEntryText.trim() === ''; useEffect(() => { const userInstruction = userInstructions?.find((entry) => !entry.public); - setNewEntryDocId(userInstruction?.doc_id); setNewEntryText(userInstruction?.text ?? ''); + setNewEntryId(userInstruction?.id); }, [userInstructions]); const handleSubmit = async () => { await createEntry({ entry: { - doc_id: newEntryDocId ?? uuidv4(), + id: newEntryId ?? uuidv4(), text: newEntryText, public: false, // limit user instructions to private (for now) }, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_tab.test.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_tab.test.tsx index d8e2897c6878..50d0cb8ba47c 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_tab.test.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_tab.test.tsx @@ -81,7 +81,18 @@ describe('KnowledgeBaseTab', () => { getByTestId('knowledgeBaseEditManualEntryFlyoutSaveButton').click(); - expect(createMock).toHaveBeenCalledWith({ entry: { id: 'foo', public: false, text: 'bar' } }); + expect(createMock).toHaveBeenCalledWith({ + entry: { + id: expect.any(String), + title: 'foo', + public: false, + text: 'bar', + role: 'user_entry', + confidence: 'high', + is_correction: false, + labels: expect.any(Object), + }, + }); }); it('should require an id', () => { @@ -126,7 +137,7 @@ describe('KnowledgeBaseTab', () => { entries: [ { id: 'test', - doc_id: 'test', + title: 'test', text: 'test', '@timestamp': 1638340456, labels: {}, @@ -134,7 +145,7 @@ describe('KnowledgeBaseTab', () => { }, { id: 'test2', - doc_id: 'test2', + title: 'test2', text: 'test', '@timestamp': 1638340456, labels: { @@ -144,7 +155,7 @@ describe('KnowledgeBaseTab', () => { }, { id: 'test3', - doc_id: 'test3', + title: 'test3', text: 'test', '@timestamp': 1638340456, labels: { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_tab.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_tab.tsx index 6ba09101b622..23fbf796290c 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_tab.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_tab.tsx @@ -57,10 +57,10 @@ export function KnowledgeBaseTab() { data-test-subj="pluginsColumnsButton" onClick={() => setSelectedCategory(category)} aria-label={ - category.categoryName === selectedCategory?.categoryName ? 'Collapse' : 'Expand' + category.categoryKey === selectedCategory?.categoryKey ? 'Collapse' : 'Expand' } iconType={ - category.categoryName === selectedCategory?.categoryName ? 'minimize' : 'expand' + category.categoryKey === selectedCategory?.categoryKey ? 'minimize' : 'expand' } /> ); @@ -85,7 +85,8 @@ export function KnowledgeBaseTab() { width: '40px', }, { - field: 'categoryName', + 'data-test-subj': 'knowledgeBaseTableTitleCell', + field: 'title', name: i18n.translate('xpack.observabilityAiAssistantManagement.kbTab.columns.name', { defaultMessage: 'Name', }), @@ -107,6 +108,7 @@ export function KnowledgeBaseTab() { }, }, { + 'data-test-subj': 'knowledgeBaseTableAuthorCell', name: i18n.translate('xpack.observabilityAiAssistantManagement.kbTab.columns.author', { defaultMessage: 'Author', }), @@ -183,7 +185,7 @@ export function KnowledgeBaseTab() { const [isNewEntryPopoverOpen, setIsNewEntryPopoverOpen] = useState(false); const [isEditUserInstructionFlyoutOpen, setIsEditUserInstructionFlyoutOpen] = useState(false); const [query, setQuery] = useState(''); - const [sortBy, setSortBy] = useState<'doc_id' | '@timestamp'>('doc_id'); + const [sortBy, setSortBy] = useState('title'); const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc'); const { @@ -193,17 +195,10 @@ export function KnowledgeBaseTab() { } = useGetKnowledgeBaseEntries({ query, sortBy, sortDirection }); const categorizedEntries = categorizeEntries({ entries }); - const handleChangeSort = ({ - sort, - }: Criteria) => { + const handleChangeSort = ({ sort }: Criteria) => { if (sort) { const { field, direction } = sort; - if (field === '@timestamp') { - setSortBy(field); - } - if (field === 'categoryName') { - setSortBy('doc_id'); - } + setSortBy(field); setSortDirection(direction); } }; @@ -329,7 +324,7 @@ export function KnowledgeBaseTab() { loading={isLoading} sorting={{ sort: { - field: sortBy === 'doc_id' ? 'categoryName' : sortBy, + field: sortBy, direction: sortDirection, }, }} diff --git a/x-pack/plugins/observability_solution/observability_logs_explorer/common/translations.ts b/x-pack/plugins/observability_solution/observability_logs_explorer/common/translations.ts index f89c6eb47e6c..380bc3c3c5a2 100644 --- a/x-pack/plugins/observability_solution/observability_logs_explorer/common/translations.ts +++ b/x-pack/plugins/observability_solution/observability_logs_explorer/common/translations.ts @@ -22,14 +22,26 @@ export const observabilityAppTitle = i18n.translate( } ); -export const betaBadgeTitle = i18n.translate('xpack.observabilityLogsExplorer.betaBadgeTitle', { - defaultMessage: 'Beta', -}); +export const deprecationBadgeTitle = i18n.translate( + 'xpack.observabilityLogsExplorer.deprecationBadgeTitle', + { + defaultMessage: 'Deprecation notice', + } +); + +export const deprecationBadgeDescription = i18n.translate( + 'xpack.observabilityLogsExplorer.deprecationBadgeDescription', + { + defaultMessage: + 'Logs Stream and Logs Explorer are set to be deprecated. Switch to Discover which now includes their functionality plus more features and better performance.', + } +); -export const betaBadgeDescription = i18n.translate( - 'xpack.observabilityLogsExplorer.betaBadgeDescription', +export const deprecationBadgeGuideline = i18n.translate( + 'xpack.observabilityLogsExplorer.deprecationBadgeGuideline', { - defaultMessage: 'This application is in beta and therefore subject to change.', + defaultMessage: + 'You can temporarily access Logs Stream by re-enabling it in Advanced Settings.', } ); diff --git a/x-pack/plugins/observability_solution/observability_logs_explorer/public/components/logs_explorer_top_nav_menu.tsx b/x-pack/plugins/observability_solution/observability_logs_explorer/public/components/logs_explorer_top_nav_menu.tsx index c3f91b3bf866..0020df30b870 100644 --- a/x-pack/plugins/observability_solution/observability_logs_explorer/public/components/logs_explorer_top_nav_menu.tsx +++ b/x-pack/plugins/observability_solution/observability_logs_explorer/public/components/logs_explorer_top_nav_menu.tsx @@ -21,7 +21,11 @@ import { LogsExplorerTabs } from '@kbn/discover-plugin/public'; import React, { useEffect, useState } from 'react'; import useObservable from 'react-use/lib/useObservable'; import { filter, take } from 'rxjs'; -import { betaBadgeDescription, betaBadgeTitle } from '../../common/translations'; +import { + deprecationBadgeDescription, + deprecationBadgeGuideline, + deprecationBadgeTitle, +} from '../../common/translations'; import { useKibanaContextForPlugin } from '../utils/use_kibana'; import { ConnectedDiscoverLink } from './discover_link'; import { FeedbackLink } from './feedback_link'; @@ -59,13 +63,7 @@ const ProjectTopNav = () => { `} > - + @@ -115,15 +113,6 @@ const ClassicTopNav = () => { margin-left: ${euiThemeVars.euiSizeM}; `} > - - - @@ -145,6 +134,9 @@ const ClassicTopNav = () => { + + + @@ -171,3 +163,19 @@ const ConditionalVerticalRule = ({ Component }: { Component: JSX.Element | null {Component} ); + +const DeprecationNoticeBadge = () => ( + + {deprecationBadgeDescription} +
    +
    + {deprecationBadgeGuideline} + + } + alignment="middle" + /> +); diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/assets/auto_detect.sh b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/auto_detect.sh index a77f24790f9d..06f6a90f82a4 100755 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/assets/auto_detect.sh +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/assets/auto_detect.sh @@ -343,6 +343,7 @@ read_open_log_file_list() { "^\/var\/log\/redis\/" "^\/var\/log\/rabbitmq\/" "^\/var\/log\/kafka\/" + "^\/var\/lib\/docker\/" "^\/var\/log\/mongodb\/" "^\/opt\/tomcat\/logs\/" "^\/var\/log\/prometheus\/" diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_control_panels_url_state.ts b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_control_panels_url_state.ts similarity index 63% rename from x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_control_panels_url_state.ts rename to x-pack/plugins/observability_solution/observability_shared/public/hooks/use_control_panels_url_state.ts index 19c0580c73f8..0ade125dcf81 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_control_panels_url_state.ts +++ b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_control_panels_url_state.ts @@ -12,85 +12,49 @@ import { fold } from 'fp-ts/lib/Either'; import { constant, identity } from 'fp-ts/lib/function'; import type { DataView } from '@kbn/data-views-plugin/public'; import { useMemo } from 'react'; -import { useUrlState } from '../../../../hooks/use_url_state'; +import { useUrlState } from './use_url_state'; -const HOST_FILTERS_URL_STATE_KEY = 'controlPanels'; +const CONTROL_PANELS_URL_KEY = 'controlPanels'; -export const availableControlsPanels = { - HOST_OS_NAME: 'host.os.name', - CLOUD_PROVIDER: 'cloud.provider', - SERVICE_NAME: 'service.name', -}; - -const controlPanelConfigs: ControlPanels = { - [availableControlsPanels.HOST_OS_NAME]: { - order: 0, - width: 'medium', - grow: false, - type: 'optionsListControl', - fieldName: availableControlsPanels.HOST_OS_NAME, - title: 'Operating System', - }, - [availableControlsPanels.CLOUD_PROVIDER]: { - order: 1, - width: 'medium', - grow: false, - type: 'optionsListControl', - fieldName: availableControlsPanels.CLOUD_PROVIDER, - title: 'Cloud Provider', - }, - [availableControlsPanels.SERVICE_NAME]: { - order: 2, - width: 'medium', - grow: false, - type: 'optionsListControl', - fieldName: availableControlsPanels.SERVICE_NAME, - title: 'Service Name', - }, -}; +const PanelRT = rt.intersection([ + rt.type({ + order: rt.number, + type: rt.string, + }), + rt.partial({ + width: rt.union([rt.literal('medium'), rt.literal('small'), rt.literal('large')]), + grow: rt.boolean, + dataViewId: rt.string, + fieldName: rt.string, + title: rt.union([rt.string, rt.undefined]), + selectedOptions: rt.array(rt.string), + }), +]); -const availableControlPanelFields = Object.values(availableControlsPanels); +const ControlPanelRT = rt.record(rt.string, PanelRT); +export type ControlPanels = rt.TypeOf; -export const useControlPanels = ( +const getVisibleControlPanels = ( + availableControlPanelFields: string[], dataView: DataView | undefined -): [ControlPanels, (state: ControlPanels) => void] => { - const defaultState = useMemo(() => getVisibleControlPanelsConfig(dataView), [dataView]); - - const [controlPanels, setControlPanels] = useUrlState({ - defaultState, - decodeUrlState, - encodeUrlState, - urlStateKey: HOST_FILTERS_URL_STATE_KEY, - }); - - /** - * Configure the control panels as - * 1. Available fields from the data view - * 2. Existing filters from the URL parameter (not colliding with allowed fields from data view) - * 3. Enhanced with dataView.id - */ - const controlsPanelsWithId = dataView - ? mergeDefaultPanelsWithUrlConfig(dataView, controlPanels) - : ({} as ControlPanels); - - return [controlsPanelsWithId, setControlPanels]; -}; - -/** - * Utils - */ -const getVisibleControlPanels = (dataView: DataView | undefined) => { +) => { return availableControlPanelFields.filter( (panelKey) => dataView?.fields.getByName(panelKey) !== undefined ); }; -const getVisibleControlPanelsConfig = (dataView: DataView | undefined) => { - return getVisibleControlPanels(dataView).reduce((panelsMap, panelKey) => { - const config = controlPanelConfigs[panelKey]; - - return { ...panelsMap, [panelKey]: config }; - }, {} as ControlPanels); +const getVisibleControlPanelsConfig = ( + controlPanelConfigs: ControlPanels, + dataView: DataView | undefined +) => { + return getVisibleControlPanels(Object.keys(controlPanelConfigs), dataView).reduce( + (panelsMap, panelKey) => { + const config = controlPanelConfigs[panelKey]; + + return { ...panelsMap, [panelKey]: config }; + }, + {} as ControlPanels + ); }; const addDataViewIdToControlPanels = (controlPanels: ControlPanels, dataViewId: string = '') => { @@ -115,9 +79,13 @@ const cleanControlPanels = (controlPanels: ControlPanels) => { }, {}); }; -const mergeDefaultPanelsWithUrlConfig = (dataView: DataView, urlPanels: ControlPanels = {}) => { +const mergeDefaultPanelsWithUrlConfig = ( + dataView: DataView, + urlPanels: ControlPanels = {}, + controlPanelConfigs: ControlPanels +) => { // Get default panel configs from existing fields in data view - const visiblePanels = getVisibleControlPanelsConfig(dataView); + const visiblePanels = getVisibleControlPanelsConfig(controlPanelConfigs, dataView); // Get list of panel which can be overridden to avoid merging additional config from url const existingKeys = Object.keys(visiblePanels); @@ -130,25 +98,6 @@ const mergeDefaultPanelsWithUrlConfig = (dataView: DataView, urlPanels: ControlP ); }; -const PanelRT = rt.intersection([ - rt.type({ - order: rt.number, - type: rt.string, - }), - rt.partial({ - width: rt.union([rt.literal('medium'), rt.literal('small'), rt.literal('large')]), - grow: rt.boolean, - dataViewId: rt.string, - fieldName: rt.string, - title: rt.union([rt.string, rt.undefined]), - selectedOptions: rt.array(rt.string), - }), -]); - -const ControlPanelRT = rt.record(rt.string, PanelRT); - -type ControlPanels = rt.TypeOf; - const encodeUrlState = (value: ControlPanels) => { if (value) { // Remove the dataView.id on update to make the control panels portable between data views @@ -163,3 +112,32 @@ const decodeUrlState = (value: unknown) => { return pipe(ControlPanelRT.decode(value), fold(constant({}), identity)); } }; + +export const useControlPanels = ( + controlPanelConfigs: ControlPanels, + dataView: DataView | undefined +): [ControlPanels, (state: ControlPanels) => void] => { + const defaultState = useMemo( + () => getVisibleControlPanelsConfig(controlPanelConfigs, dataView), + [controlPanelConfigs, dataView] + ); + + const [controlPanels, setControlPanels] = useUrlState({ + defaultState, + decodeUrlState, + encodeUrlState, + urlStateKey: CONTROL_PANELS_URL_KEY, + }); + + /** + * Configure the control panels as + * 1. Available fields from the data view + * 2. Existing filters from the URL parameter (not colliding with allowed fields from data view) + * 3. Enhanced with dataView.id + */ + const controlsPanelsWithId = dataView + ? mergeDefaultPanelsWithUrlConfig(dataView, controlPanels, controlPanelConfigs) + : ({} as ControlPanels); + + return [controlsPanelsWithId, setControlPanels]; +}; diff --git a/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_es_search.ts b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_es_search.ts index ef38cf13a8c2..1560df88c787 100644 --- a/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_es_search.ts +++ b/x-pack/plugins/observability_solution/observability_shared/public/hooks/use_es_search.ts @@ -64,7 +64,7 @@ export const useEsSearch = ({ defaultState, @@ -94,7 +94,7 @@ export const useUrlState = ({ return [state, setState] as [typeof state, typeof setState]; }; -const decodeRisonUrlState = (value: string | undefined | null): RisonValue | undefined => { +export const decodeRisonUrlState = (value: string | undefined | null): RisonValue | undefined => { try { return value ? decode(value) : undefined; } catch (error) { @@ -124,3 +124,19 @@ const replaceQueryStringInLocation = (location: Location, queryString: string): }; } }; + +const encodeRisonUrlState = (state: any) => encode(state); + +const replaceStateKeyInQueryString = + (stateKey: string, urlState: UrlState | undefined) => + (queryString: string) => { + const previousQueryValues = parse(queryString, { sort: false }); + const newValue = + typeof urlState === 'undefined' + ? previousQueryValues + : { + ...previousQueryValues, + [stateKey]: encodeRisonUrlState(urlState), + }; + return stringify(url.encodeQuery(newValue), { sort: false, encode: false }); + }; diff --git a/x-pack/plugins/observability_solution/observability_shared/public/index.ts b/x-pack/plugins/observability_solution/observability_shared/public/index.ts index d732a669e45b..bc9f2c452cc8 100644 --- a/x-pack/plugins/observability_solution/observability_shared/public/index.ts +++ b/x-pack/plugins/observability_solution/observability_shared/public/index.ts @@ -104,3 +104,7 @@ export { BottomBarActions } from './components/bottom_bar_actions/bottom_bar_act export { FieldValueSelection, FieldValueSuggestions } from './components'; export { AddDataPanel, type AddDataPanelProps } from './components/add_data_panel'; + +export { useUrlState } from './hooks/use_url_state'; +export { type ControlPanels, useControlPanels } from './hooks/use_control_panels_url_state'; +export { useKibanaQuerySettings } from './hooks/use_kibana_query_settings'; diff --git a/x-pack/plugins/observability_solution/observability_shared/tsconfig.json b/x-pack/plugins/observability_solution/observability_shared/tsconfig.json index f68649c85cea..f7b8a7ff6c57 100644 --- a/x-pack/plugins/observability_solution/observability_shared/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability_shared/tsconfig.json @@ -45,6 +45,7 @@ "@kbn/rule-data-utils", "@kbn/es-query", "@kbn/serverless", + "@kbn/data-views-plugin", ], "exclude": ["target/**/*", ".storybook/**/*.js"] } diff --git a/x-pack/plugins/observability_solution/synthetics/.buildkite/pipelines/flaky.js b/x-pack/plugins/observability_solution/synthetics/.buildkite/pipelines/flaky.js index 7a1ee5c582d7..ca024e9b4228 100644 --- a/x-pack/plugins/observability_solution/synthetics/.buildkite/pipelines/flaky.js +++ b/x-pack/plugins/observability_solution/synthetics/.buildkite/pipelines/flaky.js @@ -63,8 +63,8 @@ console.log(JSON.stringify(pipeline, null, 2)); function getBuildJob() { return { command: '.buildkite/scripts/steps/build_kibana.sh', - label: 'Build Kibana Distribution and Plugins', - agents: { queue: 'c2-8' }, + label: 'Build Kibana Distribution', + agents: { queue: 'n2-8' }, key: BUILD_UUID, if: `build.env('${KIBANA_BUILD_ID}') == null || build.env('${KIBANA_BUILD_ID}') == ''`, }; diff --git a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/synthetics_params.ts b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/synthetics_params.ts index 5393fed135b7..4107bc1efbb2 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/synthetics_params.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/synthetics_params.ts @@ -19,6 +19,8 @@ export const SyntheticsParamsReadonlyCodec = t.intersection([ }), ]); +export const SyntheticsParamsReadonlyCodecList = t.array(SyntheticsParamsReadonlyCodec); + export type SyntheticsParamsReadonly = t.TypeOf; export const SyntheticsParamsCodec = t.intersection([ diff --git a/x-pack/plugins/observability_solution/synthetics/common/saved_objects/private_locations.ts b/x-pack/plugins/observability_solution/synthetics/common/saved_objects/private_locations.ts index bb3639e81605..1b5bb92dd7d8 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/saved_objects/private_locations.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/saved_objects/private_locations.ts @@ -5,5 +5,7 @@ * 2.0. */ -export const privateLocationsSavedObjectId = 'synthetics-privates-locations-singleton'; -export const privateLocationsSavedObjectName = 'synthetics-privates-locations'; +export const legacyPrivateLocationsSavedObjectId = 'synthetics-privates-locations-singleton'; +export const legacyPrivateLocationsSavedObjectName = 'synthetics-privates-locations'; + +export const privateLocationSavedObjectName = 'synthetics-private-location'; diff --git a/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/private_locations.journey.ts b/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/private_locations.journey.ts index 9e6bb8352c35..cdc596199157 100644 --- a/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/private_locations.journey.ts +++ b/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/private_locations.journey.ts @@ -7,17 +7,14 @@ import { journey, step, before, after, expect } from '@elastic/synthetics'; import { waitForLoadingToFinish } from '@kbn/ux-plugin/e2e/journeys/utils'; +import { SyntheticsServices } from './services/synthetics_services'; import { byTestId } from '../../helpers/utils'; -import { - addTestMonitor, - cleanPrivateLocations, - cleanTestMonitors, - getPrivateLocations, -} from './services/add_monitor'; +import { addTestMonitor, cleanPrivateLocations, cleanTestMonitors } from './services/add_monitor'; import { syntheticsAppPageProvider } from '../page_objects/synthetics_app'; journey(`PrivateLocationsSettings`, async ({ page, params }) => { const syntheticsApp = syntheticsAppPageProvider({ page, kibanaUrl: params.kibanaUrl, params }); + const services = new SyntheticsServices(params); page.setDefaultTimeout(2 * 30000); @@ -78,16 +75,14 @@ journey(`PrivateLocationsSettings`, async ({ page, params }) => { await page.click('text=Private Locations'); await page.click('h1:has-text("Settings")'); - const privateLocations = await getPrivateLocations(params); + const privateLocations = await services.getPrivateLocations(); - const locations = privateLocations.attributes.locations; + expect(privateLocations.length).toBe(1); - expect(locations.length).toBe(1); - - locationId = locations[0].id; + locationId = privateLocations[0].id; await addTestMonitor(params.kibanaUrl, 'test-monitor', { - locations: [locations[0]], + locations: [privateLocations[0]], type: 'browser', }); }); diff --git a/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/services/add_monitor.ts b/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/services/add_monitor.ts index 6384179a71bb..6a527da275eb 100644 --- a/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/services/add_monitor.ts +++ b/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/services/add_monitor.ts @@ -7,10 +7,7 @@ import axios from 'axios'; import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants'; -import { - privateLocationsSavedObjectId, - privateLocationsSavedObjectName, -} from '@kbn/synthetics-plugin/common/saved_objects/private_locations'; +import { legacyPrivateLocationsSavedObjectName } from '@kbn/synthetics-plugin/common/saved_objects/private_locations'; export const enableMonitorManagedViaApi = async (kibanaUrl: string) => { try { @@ -46,21 +43,6 @@ export const addTestMonitor = async ( } }; -export const getPrivateLocations = async (params: Record) => { - const getService = params.getService; - const server = getService('kibanaServer'); - - try { - return await server.savedObjects.get({ - id: privateLocationsSavedObjectId, - type: privateLocationsSavedObjectName, - }); - } catch (e) { - // eslint-disable-next-line no-console - console.log(e); - } -}; - export const cleanTestMonitors = async (params: Record) => { const getService = params.getService; const server = getService('kibanaServer'); @@ -79,7 +61,11 @@ export const cleanPrivateLocations = async (params: Record) => { try { await server.savedObjects.clean({ - types: [privateLocationsSavedObjectName, 'ingest-agent-policies', 'ingest-package-policies'], + types: [ + legacyPrivateLocationsSavedObjectName, + 'ingest-agent-policies', + 'ingest-package-policies', + ], }); } catch (e) { // eslint-disable-next-line no-console diff --git a/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/services/synthetics_services.ts b/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/services/synthetics_services.ts index 5c356492f1c2..507efe52c453 100644 --- a/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/services/synthetics_services.ts +++ b/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/services/synthetics_services.ts @@ -10,7 +10,10 @@ import type { Client } from '@elastic/elasticsearch'; import { KbnClient } from '@kbn/test'; import pMap from 'p-map'; import { makeDownSummary, makeUpSummary } from '@kbn/observability-synthetics-test-data'; -import { SyntheticsMonitor } from '@kbn/synthetics-plugin/common/runtime_types'; +import { + SyntheticsMonitor, + SyntheticsPrivateLocations, +} from '@kbn/synthetics-plugin/common/runtime_types'; import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants'; import { journeyStart, journeySummary, step1, step2 } from './data/browser_docs'; @@ -251,4 +254,12 @@ export class SyntheticsServices { }); return connector.data; } + + async getPrivateLocations(): Promise { + const response = await this.requester.request({ + path: SYNTHETICS_API_URLS.PRIVATE_LOCATIONS, + method: 'GET', + }); + return response.data as SyntheticsPrivateLocations; + } } diff --git a/x-pack/plugins/observability_solution/synthetics/kibana.jsonc b/x-pack/plugins/observability_solution/synthetics/kibana.jsonc index 89870a9e6c88..44d549843f46 100644 --- a/x-pack/plugins/observability_solution/synthetics/kibana.jsonc +++ b/x-pack/plugins/observability_solution/synthetics/kibana.jsonc @@ -63,8 +63,7 @@ "kibanaUtils", "observability", "spaces", - "indexLifecycleManagement", "unifiedDocViewer" ] } -} \ No newline at end of file +} diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx index 814fb13a99ba..2615a65ef289 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx @@ -5,16 +5,17 @@ * 2.0. */ -import React, { useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; import { EuiConfirmModal } from '@elastic/eui'; -import { FETCH_STATUS, useFetcher } from '@kbn/observability-shared-plugin/public'; -import { toMountPoint } from '@kbn/react-kibana-mount'; import { i18n } from '@kbn/i18n'; -import { useDispatch } from 'react-redux'; -import { getGlobalParamAction, deleteGlobalParams } from '../../../state/global_params'; +import { useDispatch, useSelector } from 'react-redux'; +import { + getGlobalParamAction, + deleteGlobalParamsAction, + selectGlobalParamState, +} from '../../../state/global_params'; import { syncGlobalParamsAction } from '../../../state/settings'; -import { kibanaService } from '../../../../../utils/kibana_service'; import { NO_LABEL, YES_LABEL } from '../../monitors_page/management/monitor_list_table/labels'; import { ListParamItem } from './params_list'; @@ -25,19 +26,8 @@ export const DeleteParam = ({ items: ListParamItem[]; setIsDeleteModalVisible: React.Dispatch>; }) => { - const [isDeleting, setIsDeleting] = useState(false); - const dispatch = useDispatch(); - - const handleConfirmDelete = () => { - setIsDeleting(true); - }; - - const { status } = useFetcher(() => { - if (isDeleting) { - return deleteGlobalParams(items.map(({ id }) => id)); - } - }, [items, isDeleting]); + const { isDeleting, listOfParams } = useSelector(selectGlobalParamState); const name = items .map(({ key }) => key) @@ -45,51 +35,12 @@ export const DeleteParam = ({ .slice(0, 50); useEffect(() => { - if (!isDeleting) { - return; - } - const { coreStart, toasts } = kibanaService; - - if (status === FETCH_STATUS.FAILURE) { - toasts.addDanger( - { - title: toMountPoint( -

    - {' '} - {i18n.translate('xpack.synthetics.paramManagement.paramDeleteFailuresMessage.name', { - defaultMessage: 'Param {name} failed to delete.', - values: { name }, - })} -

    , - coreStart - ), - }, - { toastLifeTimeMs: 3000 } - ); - } else if (status === FETCH_STATUS.SUCCESS) { - toasts.addSuccess( - { - title: toMountPoint( -

    - {i18n.translate('xpack.synthetics.paramManagement.paramDeleteSuccessMessage.name', { - defaultMessage: 'Param {name} deleted successfully.', - values: { name }, - })} -

    , - coreStart - ), - }, - { toastLifeTimeMs: 3000 } - ); - dispatch(syncGlobalParamsAction.get()); - } - if (status === FETCH_STATUS.SUCCESS || status === FETCH_STATUS.FAILURE) { - setIsDeleting(false); + if (!isDeleting && (listOfParams ?? []).length === 0) { setIsDeleteModalVisible(false); dispatch(getGlobalParamAction.get()); dispatch(syncGlobalParamsAction.get()); } - }, [setIsDeleting, isDeleting, status, setIsDeleteModalVisible, name, dispatch]); + }, [isDeleting, setIsDeleteModalVisible, name, dispatch, listOfParams]); return ( setIsDeleteModalVisible(false)} - onConfirm={handleConfirmDelete} + onConfirm={() => { + dispatch(deleteGlobalParamsAction.get(items.map(({ id }) => id))); + }} cancelButtonText={NO_LABEL} confirmButtonText={YES_LABEL} buttonColor="danger" diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/global_params/params_list.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/global_params/params_list.tsx index 2ff3ea547ae9..b16dbcd686d9 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/global_params/params_list.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/global_params/params_list.tsx @@ -83,7 +83,11 @@ export const ParamsList = () => { render: (val: string[]) => { const tags = val ?? []; if (tags.length === 0) { - return --; + return ( + + {i18n.translate('xpack.synthetics.columns.TextLabel', { defaultMessage: '--' })} + + ); } return ( @@ -105,7 +109,11 @@ export const ParamsList = () => { render: (val: string[]) => { const namespaces = val ?? []; if (namespaces.length === 0) { - return --; + return ( + + {i18n.translate('xpack.synthetics.columns.TextLabel', { defaultMessage: '--' })} + + ); } return ( @@ -184,6 +192,7 @@ export const ParamsList = () => { isEditingItem={isEditingItem} setIsEditingItem={setIsEditingItem} items={items} + key="add-param-flyout" />, ]; }; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/hooks/api.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/hooks/api.ts index ad3d45d0ba80..a113f86bdfef 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/hooks/api.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/hooks/api.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PolicyFromES } from '@kbn/index-lifecycle-management-plugin/common/types'; +import { PolicyFromES } from '@kbn/index-lifecycle-management-common-shared'; import { DataStream } from '@kbn/index-management-plugin/common'; import { CatIndicesResponse } from '@elastic/elasticsearch/lib/api/types'; import { apiService } from '../../../../../utils/api_service'; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/policy_link.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/policy_link.tsx index 0c9cb465c127..3918e20bccab 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/policy_link.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/policy_link.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiIconTip, EuiLink, EuiSkeletonText, EuiToolTip, EuiText } from '@elastic/eui'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { ILM_LOCATOR_ID } from '@kbn/index-lifecycle-management-plugin/public'; +import { ILM_LOCATOR_ID } from '@kbn/index-lifecycle-management-common-shared'; import { useFetcher } from '@kbn/observability-shared-plugin/public'; import { i18n } from '@kbn/i18n'; import { useSyntheticsSettingsContext } from '../../contexts'; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/elasticsearch/api.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/elasticsearch/api.ts index 8a8bbd0b138b..8c2e14aa3c17 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/elasticsearch/api.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/elasticsearch/api.ts @@ -50,7 +50,7 @@ export const executeEsQueryAPI = async ({ operationName: name, kibanaRequest: { route: { - path: '/internal/bsearch', + path: '/internal/search', method: 'POST', }, } as any, @@ -82,7 +82,7 @@ export const executeEsQueryAPI = async ({ operationName: name, kibanaRequest: { route: { - path: '/internal/bsearch', + path: '/internal/search', method: 'POST', }, } as any, diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/actions.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/actions.ts index b1388bc2674b..0faef0079657 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/actions.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/actions.ts @@ -23,3 +23,8 @@ export const editGlobalParamAction = createAsyncAction< }, SyntheticsParams >('EDIT GLOBAL PARAM'); + +export const deleteGlobalParamsAction = createAsyncAction< + string[], + Array<{ id: string; deleted: boolean }> +>('DELETE GLOBAL PARAMS'); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/api.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/api.ts index 33eb4622bf6c..1badb74dff26 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/api.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/api.ts @@ -13,6 +13,7 @@ import { SyntheticsParams, SyntheticsParamsCodec, SyntheticsParamsReadonlyCodec, + SyntheticsParamsReadonlyCodecList, } from '../../../../../common/runtime_types'; import { apiService } from '../../../../utils/api_service/api_service'; @@ -20,14 +21,14 @@ export const getGlobalParams = async (): Promise => { return apiService.get( SYNTHETICS_API_URLS.PARAMS, { version: INITIAL_REST_VERSION }, - SyntheticsParamsReadonlyCodec + SyntheticsParamsReadonlyCodecList ); }; export const addGlobalParam = async ( paramRequest: SyntheticsParamRequest ): Promise => - apiService.post(SYNTHETICS_API_URLS.PARAMS, paramRequest, SyntheticsParamsCodec, { + apiService.post(SYNTHETICS_API_URLS.PARAMS, paramRequest, SyntheticsParamsReadonlyCodec, { version: INITIAL_REST_VERSION, }); @@ -53,11 +54,13 @@ export const editGlobalParam = async ({ ); }; -export const deleteGlobalParams = async (ids: string[]): Promise => - apiService.delete( - SYNTHETICS_API_URLS.PARAMS, - { version: INITIAL_REST_VERSION }, +export const deleteGlobalParams = async (ids: string[]): Promise => { + return await apiService.post( + SYNTHETICS_API_URLS.PARAMS + '/_bulk_delete', { ids, - } + }, + null, + { version: INITIAL_REST_VERSION } ); +}; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/effects.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/effects.ts index d5249fcfc451..f5f0c6e4ee95 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/effects.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/effects.ts @@ -8,8 +8,13 @@ import { takeLeading } from 'redux-saga/effects'; import { i18n } from '@kbn/i18n'; import { fetchEffectFactory } from '../utils/fetch_effect'; -import { addGlobalParam, editGlobalParam, getGlobalParams } from './api'; -import { addNewGlobalParamAction, editGlobalParamAction, getGlobalParamAction } from './actions'; +import { addGlobalParam, deleteGlobalParams, editGlobalParam, getGlobalParams } from './api'; +import { + addNewGlobalParamAction, + deleteGlobalParamsAction, + editGlobalParamAction, + getGlobalParamAction, +} from './actions'; export function* getGlobalParamEffect() { yield takeLeading( @@ -69,3 +74,26 @@ const editSuccessMessage = i18n.translate('xpack.synthetics.settings.editParams. const editFailureMessage = i18n.translate('xpack.synthetics.settings.editParams.fail', { defaultMessage: 'Failed to edit global parameter.', }); + +// deleteGlobalParams + +export function* deleteGlobalParamsEffect() { + yield takeLeading( + deleteGlobalParamsAction.get, + fetchEffectFactory( + deleteGlobalParams, + deleteGlobalParamsAction.success, + deleteGlobalParamsAction.fail, + deleteSuccessMessage, + deleteFailureMessage + ) + ); +} + +const deleteSuccessMessage = i18n.translate('xpack.synthetics.settings.deleteParams.success', { + defaultMessage: 'Successfully deleted global parameters.', +}); + +const deleteFailureMessage = i18n.translate('xpack.synthetics.settings.deleteParams.fail', { + defaultMessage: 'Failed to delete global parameters.', +}); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/index.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/index.ts index 89b3a0b7e190..a1e2e07ff955 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/global_params/index.ts @@ -8,7 +8,12 @@ import { createReducer } from '@reduxjs/toolkit'; import { SyntheticsParams } from '../../../../../common/runtime_types'; import { IHttpSerializedFetchError } from '..'; -import { addNewGlobalParamAction, editGlobalParamAction, getGlobalParamAction } from './actions'; +import { + addNewGlobalParamAction, + deleteGlobalParamsAction, + editGlobalParamAction, + getGlobalParamAction, +} from './actions'; export interface GlobalParamsState { isLoading?: boolean; @@ -16,6 +21,7 @@ export interface GlobalParamsState { addError: IHttpSerializedFetchError | null; editError: IHttpSerializedFetchError | null; isSaving?: boolean; + isDeleting?: boolean; savedData?: SyntheticsParams; } @@ -23,6 +29,7 @@ const initialState: GlobalParamsState = { isLoading: false, addError: null, isSaving: false, + isDeleting: false, editError: null, listOfParams: [], }; @@ -62,6 +69,16 @@ export const globalParamsReducer = createReducer(initialState, (builder) => { .addCase(editGlobalParamAction.fail, (state, action) => { state.isSaving = false; state.editError = action.payload; + }) + .addCase(deleteGlobalParamsAction.get, (state) => { + state.isDeleting = true; + }) + .addCase(deleteGlobalParamsAction.success, (state) => { + state.isDeleting = false; + state.listOfParams = []; + }) + .addCase(deleteGlobalParamsAction.fail, (state) => { + state.isDeleting = false; }); }); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/monitor_list/api.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/monitor_list/api.ts index 344897dd0eb1..bef569bf0da3 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/monitor_list/api.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/monitor_list/api.ts @@ -60,12 +60,13 @@ export const fetchDeleteMonitor = async ({ }): Promise => { const baseUrl = SYNTHETICS_API_URLS.SYNTHETICS_MONITORS; - return await apiService.delete( - baseUrl, - { version: INITIAL_REST_VERSION, spaceId }, + return await apiService.post( + baseUrl + '/_bulk_delete', { ids: configIds, - } + }, + undefined, + { version: INITIAL_REST_VERSION, spaceId } ); }; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts index 1a565fe772aa..e38a1b5ad918 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts @@ -7,7 +7,12 @@ import { all, fork } from 'redux-saga/effects'; import { getCertsListEffect } from './certs'; -import { addGlobalParamEffect, editGlobalParamEffect, getGlobalParamEffect } from './global_params'; +import { + addGlobalParamEffect, + deleteGlobalParamsEffect, + editGlobalParamEffect, + getGlobalParamEffect, +} from './global_params'; import { fetchManualTestRunsEffect } from './manual_test_runs/effects'; import { enableDefaultAlertingEffect, @@ -66,6 +71,7 @@ export const rootEffect = function* root(): Generator { fork(fetchManualTestRunsEffect), fork(addGlobalParamEffect), fork(editGlobalParamEffect), + fork(deleteGlobalParamsEffect), fork(getGlobalParamEffect), fork(getCertsListEffect), fork(getDefaultAlertingEffect), diff --git a/x-pack/plugins/observability_solution/synthetics/server/feature.ts b/x-pack/plugins/observability_solution/synthetics/server/feature.ts index c8b4b721a9ce..bf86ac7b0c89 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/feature.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/feature.ts @@ -14,7 +14,10 @@ import { 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 { privateLocationsSavedObjectName } from '../common/saved_objects/private_locations'; +import { + legacyPrivateLocationsSavedObjectName, + privateLocationSavedObjectName, +} from '../common/saved_objects/private_locations'; import { PLUGIN } from '../common/constants/plugin'; import { syntheticsSettingsObjectType, @@ -71,7 +74,8 @@ export const syntheticsFeature = { syntheticsSettingsObjectType, syntheticsMonitorType, syntheticsApiKeyObjectType, - privateLocationsSavedObjectName, + privateLocationSavedObjectName, + legacyPrivateLocationsSavedObjectName, syntheticsParamType, // uptime settings object is also registered here since feature is shared between synthetics and uptime uptimeSettingsObjectType, @@ -102,7 +106,7 @@ export const syntheticsFeature = { syntheticsSettingsObjectType, syntheticsMonitorType, syntheticsApiKeyObjectType, - privateLocationsSavedObjectName, + legacyPrivateLocationsSavedObjectName, // uptime settings object is also registered here since feature is shared between synthetics and uptime uptimeSettingsObjectType, ], diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts index 48e0de1c7fba..f9d178befeb4 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { deleteSyntheticsParamsBulkRoute } from './settings/params/delete_params_bulk'; +import { deleteSyntheticsMonitorBulkRoute } from './monitor_cruds/bulk_cruds/delete_monitor_bulk'; import { createGetDynamicSettingsRoute, createPostDynamicSettingsRoute, @@ -113,4 +115,6 @@ export const syntheticsAppPublicRestApiRoutes: SyntheticsRestApiRouteFactory[] = addSyntheticsMonitorRoute, editSyntheticsMonitorRoute, deleteSyntheticsMonitorRoute, + deleteSyntheticsMonitorBulkRoute, + deleteSyntheticsParamsBulkRoute, ]; diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor/utils.test.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor/utils.test.ts index c6bd1d330bc8..d9d1a2319605 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor/utils.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor/utils.test.ts @@ -33,6 +33,11 @@ describe('parseMonitorLocations', () => { id: 'local', isServiceManaged: true, }; + const localLoc2 = { + label: 'Local 2', + id: 'local2', + isServiceManaged: true, + }; it('should return expected', function () { const result = parseMonitorLocations({ @@ -81,6 +86,20 @@ describe('parseMonitorLocations', () => { }); }); + it('should handle editing location', function () { + const result = parseMonitorLocations( + { + locations: ['local'], + } as any, + [localLoc, localLoc2] + ); + + expect(result).toEqual({ + locations: ['local'], + privateLocations: [], + }); + }); + it('should add private locations to existing', function () { const result = parseMonitorLocations( { @@ -91,7 +110,7 @@ describe('parseMonitorLocations', () => { expect(result).toEqual({ locations: ['local'], - privateLocations: ['test-private-location-2', 'test-private-location'], + privateLocations: ['test-private-location-2'], }); }); @@ -185,4 +204,19 @@ describe('parseMonitorLocations', () => { privateLocations: [], }); }); + + it('should handle private location objects', function () { + const result = parseMonitorLocations( + { + locations: [pvtLoc1], + } as any, + [localLoc, pvtLoc1], + true + ); + + expect(result).toEqual({ + locations: [], + privateLocations: ['test-private-location'], + }); + }); }); diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor/utils.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor/utils.ts index 0d096ee21745..2c58e868d827 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor/utils.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/add_monitor/utils.ts @@ -25,7 +25,7 @@ export const getPrivateLocationsForMonitor = async ( export const parseMonitorLocations = ( monitorPayload: CreateMonitorPayLoad, prevLocations?: MonitorFields['locations'], - internal: boolean = false + internal = false ) => { const { locations, private_locations: privateLocations } = monitorPayload; @@ -42,41 +42,33 @@ export const parseMonitorLocations = ( pvtLocs = prevLocations.filter((loc) => !loc.isServiceManaged).map((loc) => loc.id); } else { if (prevLocations && !internal) { + const prevPublicLocs = prevLocations + .filter((loc) => loc.isServiceManaged) + .map((loc) => loc.id); + const prevPrivateLocs = prevLocations + .filter((loc) => !loc.isServiceManaged) + .map((loc) => loc.id); + if (!locations && !privateLocations) { - locs = prevLocations.filter((loc) => loc.isServiceManaged).map((loc) => loc.id); - pvtLocs = prevLocations.filter((loc) => !loc.isServiceManaged).map((loc) => loc.id); + locs = prevPublicLocs; + pvtLocs = prevPrivateLocs; } else { if (!privateLocations) { - pvtLocs = [ - ...(pvtLocs ?? []), - ...prevLocations.filter((loc) => !loc.isServiceManaged).map((loc) => loc.id), - ]; + pvtLocs = [...(pvtLocs ?? []), ...prevPrivateLocs]; if (locations?.length === 0) { locs = []; - } else { - locs = [ - ...(locs ?? []), - ...prevLocations.filter((loc) => loc.isServiceManaged).map((loc) => loc.id), - ]; } } if (!locations) { - locs = [ - ...(locs ?? []), - ...prevLocations.filter((loc) => loc.isServiceManaged).map((loc) => loc.id), - ]; + locs = [...(locs ?? []), ...prevPublicLocs]; if (privateLocations?.length === 0) { pvtLocs = []; - } else { - pvtLocs = [ - ...(pvtLocs ?? []), - ...prevLocations.filter((loc) => !loc.isServiceManaged).map((loc) => loc.id), - ]; } } } } } + return { locations: Array.from(new Set(locs)), privateLocations: Array.from(new Set(pvtLocs)), diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/add_monitor_bulk.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/add_monitor_bulk.ts index 2ecbbf83d471..03c7ede49ceb 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/add_monitor_bulk.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/add_monitor_bulk.ts @@ -10,7 +10,6 @@ import { SavedObjectsBulkResponse } from '@kbn/core-saved-objects-api-server'; import { v4 as uuidV4 } from 'uuid'; import { NewPackagePolicy } from '@kbn/fleet-plugin/common'; import { SavedObjectError } from '@kbn/core-saved-objects-common'; -import { deleteMonitorBulk } from './delete_monitor_bulk'; import { SyntheticsServerSetup } from '../../../types'; import { RouteContext } from '../../types'; import { formatTelemetryEvent, sendTelemetryEvents } from '../../telemetry/monitor_upgrade_sender'; @@ -190,9 +189,10 @@ export const deleteMonitorIfCreated = async ({ newMonitorId ); if (encryptedMonitor) { - await deleteMonitorBulk({ + const deleteMonitorAPI = new DeleteMonitorAPI(routeContext); + + await deleteMonitorAPI.deleteMonitorBulk({ monitors: [encryptedMonitor], - routeContext, }); } } catch (e) { diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/delete_monitor_bulk.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/delete_monitor_bulk.ts index 9a031b3e7111..ba6426de740d 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/delete_monitor_bulk.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/bulk_cruds/delete_monitor_bulk.ts @@ -4,63 +4,40 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { SavedObject } from '@kbn/core-saved-objects-server'; -import { - formatTelemetryDeleteEvent, - sendTelemetryEvents, -} from '../../telemetry/monitor_upgrade_sender'; -import { - ConfigKey, - MonitorFields, - SyntheticsMonitor, - EncryptedSyntheticsMonitorAttributes, - SyntheticsMonitorWithId, -} from '../../../../common/runtime_types'; -import { syntheticsMonitorType } from '../../../../common/types/saved_objects'; -import { RouteContext } from '../../types'; -export const deleteMonitorBulk = async ({ - monitors, - routeContext, -}: { - monitors: Array>; - routeContext: RouteContext; -}) => { - const { savedObjectsClient, server, spaceId, syntheticsMonitorClient } = routeContext; - const { logger, telemetry, stackVersion } = server; +import { schema } from '@kbn/config-schema'; +import { DeleteMonitorAPI } from '../services/delete_monitor_api'; +import { SYNTHETICS_API_URLS } from '../../../../common/constants'; +import { SyntheticsRestApiRouteFactory } from '../../types'; - try { - const deleteSyncPromise = syntheticsMonitorClient.deleteMonitors( - monitors.map((normalizedMonitor) => ({ - ...normalizedMonitor.attributes, - id: normalizedMonitor.attributes[ConfigKey.MONITOR_QUERY_ID], - })) as SyntheticsMonitorWithId[], - savedObjectsClient, - spaceId - ); +export const deleteSyntheticsMonitorBulkRoute: SyntheticsRestApiRouteFactory< + Array<{ id: string; deleted: boolean }>, + Record, + Record, + { ids: string[] } +> = () => ({ + method: 'POST', + path: SYNTHETICS_API_URLS.SYNTHETICS_MONITORS + '/_bulk_delete', + validate: {}, + validation: { + request: { + body: schema.object({ + ids: schema.arrayOf(schema.string(), { + minSize: 1, + }), + }), + }, + }, + handler: async (routeContext): Promise => { + const { request } = routeContext; - const deletePromises = savedObjectsClient.bulkDelete( - monitors.map((monitor) => ({ type: syntheticsMonitorType, id: monitor.id })) - ); + const { ids: idsToDelete } = request.body || {}; + const deleteMonitorAPI = new DeleteMonitorAPI(routeContext); - const [errors, result] = await Promise.all([deleteSyncPromise, deletePromises]); - - monitors.forEach((monitor) => { - sendTelemetryEvents( - logger, - telemetry, - formatTelemetryDeleteEvent( - monitor, - stackVersion, - new Date().toISOString(), - Boolean((monitor.attributes as MonitorFields)[ConfigKey.SOURCE_INLINE]), - errors - ) - ); + const { errors, result } = await deleteMonitorAPI.execute({ + monitorIds: idsToDelete, }); - return { errors, result }; - } catch (e) { - throw e; - } -}; + return { result, errors }; + }, +}); diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor.ts index f40f06f66b1f..b989d16e4f19 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { i18n } from '@kbn/i18n'; import { schema } from '@kbn/config-schema'; import { DeleteMonitorAPI } from './services/delete_monitor_api'; import { SyntheticsRestApiRouteFactory } from '../types'; @@ -41,30 +42,39 @@ export const deleteSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory< if (ids && queryId) { return response.badRequest({ - body: { message: 'id must be provided either via param or body.' }, + body: { + message: i18n.translate('xpack.synthetics.deleteMonitor.errorMultipleIdsProvided', { + defaultMessage: 'id must be provided either via param or body.', + }), + }, }); } const idsToDelete = [...(ids ?? []), ...(queryId ? [queryId] : [])]; if (idsToDelete.length === 0) { return response.badRequest({ - body: { message: 'id must be provided via param or body.' }, + body: { + message: i18n.translate('xpack.synthetics.deleteMonitor.errorMultipleIdsProvided', { + defaultMessage: 'id must be provided either via param or body.', + }), + }, }); } const deleteMonitorAPI = new DeleteMonitorAPI(routeContext); - try { - const { errors } = await deleteMonitorAPI.execute({ - monitorIds: idsToDelete, - }); + const { errors } = await deleteMonitorAPI.execute({ + monitorIds: idsToDelete, + }); - if (errors && errors.length > 0) { - return response.ok({ - body: { message: 'error pushing monitor to the service', attributes: { errors } }, - }); - } - } catch (getErr) { - throw getErr; + if (errors && errors.length > 0) { + return response.ok({ + body: { + message: i18n.translate('xpack.synthetics.deleteMonitor.errorPushingMonitorToService', { + defaultMessage: 'Error pushing monitor to the service', + }), + attributes: { errors }, + }, + }); } return deleteMonitorAPI.result; diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor_project.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor_project.ts index 7b3678093769..a56f66842a70 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor_project.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/delete_monitor_project.ts @@ -6,12 +6,12 @@ */ import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; +import { DeleteMonitorAPI } from './services/delete_monitor_api'; import { SyntheticsRestApiRouteFactory } from '../types'; import { syntheticsMonitorType } from '../../../common/types/saved_objects'; import { ConfigKey } from '../../../common/runtime_types'; import { SYNTHETICS_API_URLS } from '../../../common/constants'; import { getMonitors, getSavedObjectKqlFilter } from '../common'; -import { deleteMonitorBulk } from './bulk_cruds/delete_monitor_bulk'; import { validateSpaceId } from './services/validate_space_id'; export const deleteSyntheticsMonitorProjectRoute: SyntheticsRestApiRouteFactory = () => ({ @@ -58,9 +58,10 @@ export const deleteSyntheticsMonitorProjectRoute: SyntheticsRestApiRouteFactory { fields: [] } ); - await deleteMonitorBulk({ + const deleteMonitorAPI = new DeleteMonitorAPI(routeContext); + + await deleteMonitorAPI.deleteMonitorBulk({ monitors, - routeContext, }); return { diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.test.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.test.ts index 637c0fc5c619..cb50708c04ec 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.test.ts @@ -33,6 +33,16 @@ describe('syncEditedMonitor', () => { bulkUpdate: jest.fn(), get: jest.fn(), update: jest.fn(), + createPointInTimeFinder: jest.fn().mockImplementation(({ perPage, type: soType }) => ({ + close: jest.fn(async () => {}), + find: jest.fn().mockReturnValue({ + async *[Symbol.asyncIterator]() { + yield { + saved_objects: [], + }; + }, + }), + })), }, logger, config: { diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/services/delete_monitor_api.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/services/delete_monitor_api.ts index bd162fc04359..4fc527f93083 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/services/delete_monitor_api.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/services/delete_monitor_api.ts @@ -7,16 +7,22 @@ import pMap from 'p-map'; import { SavedObject, SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server'; -import { deleteMonitorBulk } from '../bulk_cruds/delete_monitor_bulk'; import { validatePermissions } from '../edit_monitor'; import { + ConfigKey, EncryptedSyntheticsMonitorAttributes, + MonitorFields, SyntheticsMonitor, + SyntheticsMonitorWithId, SyntheticsMonitorWithSecretsAttributes, } from '../../../../common/runtime_types'; import { syntheticsMonitorType } from '../../../../common/types/saved_objects'; import { normalizeSecrets } from '../../../synthetics_service/utils'; -import { sendErrorTelemetryEvents } from '../../telemetry/monitor_upgrade_sender'; +import { + formatTelemetryDeleteEvent, + sendErrorTelemetryEvents, + sendTelemetryEvents, +} from '../../telemetry/monitor_upgrade_sender'; import { RouteContext } from '../../types'; export class DeleteMonitorAPI { @@ -100,9 +106,8 @@ export class DeleteMonitorAPI { } try { - const { errors, result } = await deleteMonitorBulk({ + const { errors, result } = await this.deleteMonitorBulk({ monitors, - routeContext: this.routeContext, }); result.statuses?.forEach((res) => { @@ -112,11 +117,55 @@ export class DeleteMonitorAPI { }); }); - return { errors }; + return { errors, result: this.result }; } catch (e) { server.logger.error(`Unable to delete Synthetics monitor with error ${e.message}`); server.logger.error(e); throw e; } } + + async deleteMonitorBulk({ + monitors, + }: { + monitors: Array>; + }) { + const { savedObjectsClient, server, spaceId, syntheticsMonitorClient } = this.routeContext; + const { logger, telemetry, stackVersion } = server; + + try { + const deleteSyncPromise = syntheticsMonitorClient.deleteMonitors( + monitors.map((normalizedMonitor) => ({ + ...normalizedMonitor.attributes, + id: normalizedMonitor.attributes[ConfigKey.MONITOR_QUERY_ID], + })) as SyntheticsMonitorWithId[], + savedObjectsClient, + spaceId + ); + + const deletePromises = savedObjectsClient.bulkDelete( + monitors.map((monitor) => ({ type: syntheticsMonitorType, id: monitor.id })) + ); + + const [errors, result] = await Promise.all([deleteSyncPromise, deletePromises]); + + monitors.forEach((monitor) => { + sendTelemetryEvents( + logger, + telemetry, + formatTelemetryDeleteEvent( + monitor, + stackVersion, + new Date().toISOString(), + Boolean((monitor.attributes as MonitorFields)[ConfigKey.SOURCE_INLINE]), + errors + ) + ); + }); + + return { errors, result }; + } catch (e) { + throw e; + } + } } diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/params/delete_param.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/params/delete_param.ts index 78d24d9452ae..1a504b263861 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/params/delete_param.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/params/delete_param.ts @@ -6,6 +6,7 @@ */ import { schema } from '@kbn/config-schema'; +import { i18n } from '@kbn/i18n'; import { SyntheticsRestApiRouteFactory } from '../../types'; import { syntheticsParamType } from '../../../../common/types/saved_objects'; import { SYNTHETICS_API_URLS } from '../../../../common/constants'; @@ -13,25 +14,51 @@ import { DeleteParamsResponse } from '../../../../common/runtime_types'; export const deleteSyntheticsParamsRoute: SyntheticsRestApiRouteFactory< DeleteParamsResponse[], - unknown, + { id?: string }, unknown, { ids: string[] } > = () => ({ method: 'DELETE', - path: SYNTHETICS_API_URLS.PARAMS, + path: SYNTHETICS_API_URLS.PARAMS + '/{id?}', validate: {}, validation: { request: { - body: schema.object({ - ids: schema.arrayOf(schema.string()), + body: schema.nullable( + schema.object({ + ids: schema.arrayOf(schema.string(), { + minSize: 1, + }), + }) + ), + params: schema.object({ + id: schema.maybe(schema.string()), }), }, }, - handler: async ({ savedObjectsClient, request }) => { - const { ids } = request.body; + handler: async ({ savedObjectsClient, request, response }) => { + const { ids } = request.body ?? {}; + const { id: paramId } = request.params ?? {}; + + if (ids && paramId) { + return response.badRequest({ + body: i18n.translate('xpack.synthetics.deleteParam.errorMultipleIdsProvided', { + defaultMessage: `Both param id and body parameters cannot be provided`, + }), + }); + } + + const idsToDelete = ids ?? [paramId]; + + if (idsToDelete.length === 0) { + return response.badRequest({ + body: i18n.translate('xpack.synthetics.deleteParam.errorNoIdsProvided', { + defaultMessage: `No param ids provided`, + }), + }); + } const result = await savedObjectsClient.bulkDelete( - ids.map((id) => ({ type: syntheticsParamType, id })), + idsToDelete.map((id) => ({ type: syntheticsParamType, id })), { force: true } ); return result.statuses.map(({ id, success }) => ({ id, deleted: success })); diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/params/delete_params_bulk.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/params/delete_params_bulk.ts new file mode 100644 index 000000000000..2cafaf0a1af9 --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/params/delete_params_bulk.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { SyntheticsRestApiRouteFactory } from '../../types'; +import { syntheticsParamType } from '../../../../common/types/saved_objects'; +import { SYNTHETICS_API_URLS } from '../../../../common/constants'; +import { DeleteParamsResponse } from '../../../../common/runtime_types'; + +export const deleteSyntheticsParamsBulkRoute: SyntheticsRestApiRouteFactory< + DeleteParamsResponse[], + unknown, + unknown, + { ids: string[] } +> = () => ({ + method: 'POST', + path: SYNTHETICS_API_URLS.PARAMS + '/_bulk_delete', + validate: {}, + validation: { + request: { + body: schema.object({ + ids: schema.arrayOf(schema.string()), + }), + }, + }, + handler: async ({ savedObjectsClient, request }) => { + const { ids } = request.body; + + const result = await savedObjectsClient.bulkDelete( + ids.map((id) => ({ type: syntheticsParamType, id })), + { force: true } + ); + return result.statuses.map(({ id, success }) => ({ id, deleted: success })); + }, +}); 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 ac6eff7dea90..1feb120b2ea1 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,14 +6,12 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations'; import { SyntheticsRestApiRouteFactory } from '../../types'; import { getPrivateLocationsAndAgentPolicies } from './get_private_locations'; -import { - privateLocationsSavedObjectId, - privateLocationsSavedObjectName, -} from '../../../../common/saved_objects/private_locations'; +import { privateLocationSavedObjectName } from '../../../../common/saved_objects/private_locations'; import { SYNTHETICS_API_URLS } from '../../../../common/constants'; -import type { SyntheticsPrivateLocationsAttributes } from '../../../runtime_types/private_locations'; +import { PrivateLocationAttributes } from '../../../runtime_types/private_locations'; import { toClientContract, toSavedObjectContract } from './helpers'; import { PrivateLocation } from '../../../../common/runtime_types'; @@ -40,7 +38,11 @@ export const addPrivateLocationRoute: SyntheticsRestApiRouteFactory { + handler: async (routeContext) => { + await migrateLegacyPrivateLocations(routeContext); + + const { response, request, savedObjectsClient, syntheticsMonitorClient } = routeContext; + const location = request.body as PrivateLocationObject; const { locations, agentPolicies } = await getPrivateLocationsAndAgentPolicies( @@ -65,7 +67,6 @@ export const addPrivateLocationRoute: SyntheticsRestApiRouteFactory loc.id !== location.agentPolicyId); const formattedLocation = toSavedObjectContract({ ...location, id: location.agentPolicyId, @@ -80,17 +81,17 @@ export const addPrivateLocationRoute: SyntheticsRestApiRouteFactory( - privateLocationsSavedObjectName, - { locations: [...existingLocations, formattedLocation] }, + const soClient = routeContext.server.coreStart.savedObjects.createInternalRepository(); + + const result = await soClient.create( + privateLocationSavedObjectName, + formattedLocation, { - id: privateLocationsSavedObjectId, - overwrite: true, + id: location.agentPolicyId, + initialNamespaces: ['*'], } ); - const allLocations = toClientContract(result.attributes, agentPolicies); - - return allLocations.find((loc) => loc.id === location.agentPolicyId)!; + return toClientContract(result.attributes, agentPolicies); }, }); 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 1c6ede5a2ad0..bac3907eac87 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,15 +7,12 @@ import { schema } from '@kbn/config-schema'; import { isEmpty } from 'lodash'; +import { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations'; import { getMonitorsByLocation } from './get_location_monitors'; import { getPrivateLocationsAndAgentPolicies } from './get_private_locations'; import { SyntheticsRestApiRouteFactory } from '../../types'; import { SYNTHETICS_API_URLS } from '../../../../common/constants'; -import { - privateLocationsSavedObjectId, - privateLocationsSavedObjectName, -} from '../../../../common/saved_objects/private_locations'; -import type { SyntheticsPrivateLocationsAttributes } from '../../../runtime_types/private_locations'; +import { privateLocationSavedObjectName } from '../../../../common/saved_objects/private_locations'; export const deletePrivateLocationRoute: SyntheticsRestApiRouteFactory = () => ({ method: 'DELETE', @@ -28,12 +25,16 @@ export const deletePrivateLocationRoute: SyntheticsRestApiRouteFactory { + handler: async (routeContext) => { + await migrateLegacyPrivateLocations(routeContext); + + const { savedObjectsClient, syntheticsMonitorClient, request, response, server } = routeContext; const { locationId } = request.params as { locationId: string }; const { locations } = await getPrivateLocationsAndAgentPolicies( savedObjectsClient, - syntheticsMonitorClient + syntheticsMonitorClient, + true ); if (!locations.find((loc) => loc.id === locationId)) { @@ -55,17 +56,8 @@ export const deletePrivateLocationRoute: SyntheticsRestApiRouteFactory loc.id !== locationId); - - await savedObjectsClient.create( - privateLocationsSavedObjectName, - { locations: remainingLocations }, - { - id: privateLocationsSavedObjectId, - overwrite: true, - } - ); - - return; + await savedObjectsClient.delete(privateLocationSavedObjectName, locationId, { + force: true, + }); }, }); 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 f7adc1e7ac16..d884bba5c2b0 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 @@ -7,6 +7,7 @@ import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { schema } from '@kbn/config-schema'; +import { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations'; import { AgentPolicyInfo } from '../../../../common/types'; import { SyntheticsRestApiRouteFactory } from '../../types'; import { PrivateLocation, SyntheticsPrivateLocations } from '../../../../common/runtime_types'; @@ -14,7 +15,7 @@ import { SYNTHETICS_API_URLS } from '../../../../common/constants'; import { getPrivateLocations } from '../../../synthetics_service/get_private_locations'; import type { SyntheticsPrivateLocationsAttributes } from '../../../runtime_types/private_locations'; import { SyntheticsMonitorClient } from '../../../synthetics_service/synthetics_monitor/synthetics_monitor_client'; -import { toClientContract } from './helpers'; +import { allLocationsToClientContract } from './helpers'; export const getPrivateLocationsRoute: SyntheticsRestApiRouteFactory< SyntheticsPrivateLocations | PrivateLocation @@ -29,14 +30,17 @@ export const getPrivateLocationsRoute: SyntheticsRestApiRouteFactory< }), }, }, - handler: async ({ savedObjectsClient, syntheticsMonitorClient, request, response }) => { + handler: async (routeContext) => { + await migrateLegacyPrivateLocations(routeContext); + + const { savedObjectsClient, syntheticsMonitorClient, request, response } = routeContext; const { id } = request.params as { id?: string }; const { locations, agentPolicies } = await getPrivateLocationsAndAgentPolicies( savedObjectsClient, syntheticsMonitorClient ); - const list = toClientContract({ locations }, agentPolicies); + const list = allLocationsToClientContract({ locations }, agentPolicies); if (!id) return list; const location = list.find((loc) => loc.id === id || loc.label === id); if (!location) { @@ -53,7 +57,7 @@ export const getPrivateLocationsRoute: SyntheticsRestApiRouteFactory< export const getPrivateLocationsAndAgentPolicies = async ( savedObjectsClient: SavedObjectsClientContract, syntheticsMonitorClient: SyntheticsMonitorClient, - excludeAgentPolicies: boolean = false + excludeAgentPolicies = false ): Promise => { try { const [privateLocations, agentPolicies] = await Promise.all([ diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/helpers.test.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/helpers.test.ts index 6055b217f879..84c531cb9ce7 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/helpers.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/helpers.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { toClientContract } from './helpers'; +import { allLocationsToClientContract } from './helpers'; const testLocations = { locations: [ @@ -56,7 +56,7 @@ const testLocations2 = { describe('toClientContract', () => { it('formats SO attributes to client contract with falsy geo location', () => { // @ts-ignore fixtures are purposely wrong types for testing - expect(toClientContract(testLocations)).toEqual([ + expect(allLocationsToClientContract(testLocations)).toEqual([ { agentPolicyId: 'e3134290-0f73-11ee-ba15-159f4f728deb', geo: { @@ -86,7 +86,7 @@ describe('toClientContract', () => { it('formats SO attributes to client contract with truthy geo location', () => { // @ts-ignore fixtures are purposely wrong types for testing - expect(toClientContract(testLocations2)).toEqual([ + expect(allLocationsToClientContract(testLocations2)).toEqual([ { agentPolicyId: 'e3134290-0f73-11ee-ba15-159f4f728deb', geo: { diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/helpers.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/helpers.ts index 1c6c03067a81..8df065ad3e48 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/helpers.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/helpers.ts @@ -13,6 +13,22 @@ import type { import { PrivateLocation } from '../../../../common/runtime_types'; export const toClientContract = ( + location: PrivateLocationAttributes, + agentPolicies?: AgentPolicyInfo[] +): PrivateLocation => { + const agPolicy = agentPolicies?.find((policy) => policy.id === location.agentPolicyId); + return { + label: location.label, + id: location.id, + agentPolicyId: location.agentPolicyId, + isServiceManaged: false, + isInvalid: !Boolean(agPolicy), + tags: location.tags, + geo: location.geo, + }; +}; + +export const allLocationsToClientContract = ( attributes: SyntheticsPrivateLocationsAttributes, agentPolicies?: AgentPolicyInfo[] ): SyntheticsPrivateLocations => { 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 new file mode 100644 index 000000000000..2305853aab3f --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.test.ts @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations'; +import { SyntheticsServerSetup } from '../../../types'; +import { coreMock, savedObjectsClientMock } from '@kbn/core/server/mocks'; +import { loggerMock } from '@kbn/logging-mocks'; +import { + type ISavedObjectsRepository, + SavedObjectsClientContract, +} from '@kbn/core-saved-objects-api-server'; + +describe('migrateLegacyPrivateLocations', () => { + let serverMock: SyntheticsServerSetup; + let savedObjectsClient: jest.Mocked; + let repositoryMock: ISavedObjectsRepository; + 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); + }); + + it('should get the legacy private locations', async () => { + savedObjectsClient.get.mockResolvedValueOnce({ + attributes: { locations: [{ id: '1', label: 'Location 1' }] }, + } as any); + savedObjectsClient.find.mockResolvedValueOnce({ total: 1 } as any); + + await migrateLegacyPrivateLocations({ + server: serverMock, + savedObjectsClient, + } as any); + + expect(savedObjectsClient.get).toHaveBeenCalledWith( + 'synthetics-privates-locations', + 'synthetics-privates-locations-singleton' + ); + }); + + 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, + } as any); + + expect(serverMock.logger.error).toHaveBeenCalledWith( + `Error getting legacy private locations: ${error}` + ); + expect(repositoryMock.bulkCreate).not.toHaveBeenCalled(); + }); + + it('should return if there are no legacy locations', async () => { + savedObjectsClient.get.mockResolvedValueOnce({ + attributes: { locations: [] }, + } as any); + + await migrateLegacyPrivateLocations({ + server: serverMock, + savedObjectsClient: savedObjectsClientMock, + } as any); + + 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({ + attributes: { locations: legacyLocations }, + } as any); + savedObjectsClient.find.mockResolvedValueOnce({ total: 1 } as any); + + await migrateLegacyPrivateLocations({ + server: serverMock, + savedObjectsClient, + } as any); + + expect(repositoryMock.bulkCreate).toHaveBeenCalledWith( + legacyLocations.map((location) => ({ + id: location.id, + attributes: location, + type: 'synthetics-private-location', + initialNamespaces: ['*'], + })), + { overwrite: true } + ); + }); + + it('should delete legacy private locations if bulk create count matches', async () => { + const legacyLocations = [{ id: '1', label: 'Location 1' }]; + savedObjectsClient.get.mockResolvedValueOnce({ + attributes: { locations: legacyLocations }, + } as any); + savedObjectsClient.find.mockResolvedValueOnce({ total: 1 } as any); + + await migrateLegacyPrivateLocations({ + server: serverMock, + savedObjectsClient, + } as any); + + expect(savedObjectsClient.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 new file mode 100644 index 000000000000..cd73e27b950e --- /dev/null +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.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 { SavedObject } from '@kbn/core-saved-objects-server'; +import { + type PrivateLocationAttributes, + SyntheticsPrivateLocationsAttributes, +} from '../../../runtime_types/private_locations'; +import { + legacyPrivateLocationsSavedObjectId, + legacyPrivateLocationsSavedObjectName, + privateLocationSavedObjectName, +} from '../../../../common/saved_objects/private_locations'; +import { RouteContext } from '../../types'; + +export const migrateLegacyPrivateLocations = async ({ + server, + savedObjectsClient, +}: RouteContext) => { + try { + let obj: SavedObject | undefined; + try { + obj = await savedObjectsClient.get( + legacyPrivateLocationsSavedObjectName, + legacyPrivateLocationsSavedObjectId + ); + } catch (e) { + server.logger.error(`Error getting legacy private locations: ${e}`); + return; + } + const legacyLocations = obj?.attributes.locations ?? []; + if (legacyLocations.length === 0) { + return; + } + + const soClient = server.coreStart.savedObjects.createInternalRepository(); + + await soClient.bulkCreate( + legacyLocations.map((location) => ({ + id: location.id, + attributes: location, + type: privateLocationSavedObjectName, + initialNamespaces: ['*'], + })), + { + overwrite: true, + } + ); + + const { total } = await savedObjectsClient.find({ + type: privateLocationSavedObjectName, + fields: [], + perPage: 0, + }); + + if (total === legacyLocations.length) { + await savedObjectsClient.delete( + legacyPrivateLocationsSavedObjectName, + legacyPrivateLocationsSavedObjectId, + {} + ); + } + } catch (e) { + server.logger.error(`Error migrating legacy private locations: ${e}`); + } +}; diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/synthetics_service/get_service_locations.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/synthetics_service/get_service_locations.ts index a9142170c9e2..ca704cdff1b2 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/synthetics_service/get_service_locations.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/synthetics_service/get_service_locations.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { toClientContract } from '../settings/private_locations/helpers'; +import { allLocationsToClientContract } from '../settings/private_locations/helpers'; import { getPrivateLocationsAndAgentPolicies } from '../settings/private_locations/get_private_locations'; import { SyntheticsRestApiRouteFactory } from '../types'; import { getAllLocations } from '../../synthetics_service/get_all_locations'; @@ -45,7 +45,7 @@ export const getServiceLocationsRoute: SyntheticsRestApiRouteFactory = () => ({ const { locations: privateLocations, agentPolicies } = await getPrivateLocationsAndAgentPolicies(savedObjectsClient, syntheticsMonitorClient); - const result = toClientContract({ locations: privateLocations }, agentPolicies); + const result = allLocationsToClientContract({ locations: privateLocations }, agentPolicies); return { locations: result, }; diff --git a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/migrations/private_locations/model_version_1.test.ts b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/migrations/private_locations/model_version_1.test.ts index 63a9f940143a..dbcdea546a9f 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/migrations/private_locations/model_version_1.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/migrations/private_locations/model_version_1.test.ts @@ -5,7 +5,7 @@ * 2.0. */ import { transformGeoProperty } from './model_version_1'; -import { privateLocationsSavedObjectName } from '../../../../common/saved_objects/private_locations'; +import { legacyPrivateLocationsSavedObjectName } from '../../../../common/saved_objects/private_locations'; describe('model version 1 migration', () => { const testLocation = { @@ -19,7 +19,7 @@ describe('model version 1 migration', () => { concurrentMonitors: 1, }; const testObject = { - type: privateLocationsSavedObjectName, + type: legacyPrivateLocationsSavedObjectName, id: 'synthetics-privates-locations-singleton', attributes: { locations: [testLocation], diff --git a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/private_locations.ts b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/private_locations.ts index ee7426ead23a..370c8d203dff 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/private_locations.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/private_locations.ts @@ -7,11 +7,33 @@ import { SavedObjectsType } from '@kbn/core/server'; import { modelVersion1 } from './migrations/private_locations/model_version_1'; -import { privateLocationsSavedObjectName } from '../../common/saved_objects/private_locations'; -export const privateLocationsSavedObjectId = 'synthetics-privates-locations-singleton'; +import { + legacyPrivateLocationsSavedObjectName, + privateLocationSavedObjectName, +} from '../../common/saved_objects/private_locations'; -export const PRIVATE_LOCATIONS_SAVED_OBJECT_TYPE: SavedObjectsType = { - name: privateLocationsSavedObjectName, +export const PRIVATE_LOCATION_SAVED_OBJECT_TYPE: SavedObjectsType = { + name: privateLocationSavedObjectName, + hidden: false, + namespaceType: 'multiple', + mappings: { + dynamic: false, + properties: { + /* Leaving these commented to make it clear that these fields exist, even though we don't want them indexed. + When adding new fields please add them here. If they need to be searchable put them in the uncommented + part of properties. + */ + }, + }, + management: { + importableAndExportable: true, + }, +}; + +export const legacyPrivateLocationsSavedObjectId = 'synthetics-privates-locations-singleton'; + +export const LEGACY_PRIVATE_LOCATIONS_SAVED_OBJECT_TYPE: SavedObjectsType = { + name: legacyPrivateLocationsSavedObjectName, hidden: false, namespaceType: 'agnostic', mappings: { diff --git a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/saved_objects.ts b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/saved_objects.ts index 9b4a365941a7..d59ecb507166 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/saved_objects.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/saved_objects.ts @@ -24,7 +24,10 @@ import { SYNTHETICS_SECRET_ENCRYPTED_TYPE, syntheticsParamSavedObjectType, } from './synthetics_param'; -import { PRIVATE_LOCATIONS_SAVED_OBJECT_TYPE } from './private_locations'; +import { + LEGACY_PRIVATE_LOCATIONS_SAVED_OBJECT_TYPE, + PRIVATE_LOCATION_SAVED_OBJECT_TYPE, +} from './private_locations'; import { DYNAMIC_SETTINGS_DEFAULT_ATTRIBUTES } from '../constants/settings'; import { DynamicSettingsAttributes } from '../runtime_types/settings'; import { @@ -37,7 +40,8 @@ export const registerSyntheticsSavedObjects = ( savedObjectsService: SavedObjectsServiceSetup, encryptedSavedObjects: EncryptedSavedObjectsPluginSetup ) => { - savedObjectsService.registerType(PRIVATE_LOCATIONS_SAVED_OBJECT_TYPE); + savedObjectsService.registerType(LEGACY_PRIVATE_LOCATIONS_SAVED_OBJECT_TYPE); + savedObjectsService.registerType(PRIVATE_LOCATION_SAVED_OBJECT_TYPE); savedObjectsService.registerType(getSyntheticsMonitorSavedObjectType(encryptedSavedObjects)); savedObjectsService.registerType(syntheticsServiceApiKey); diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/get_all_locations.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/get_all_locations.ts index c24b28c00ca9..0d8355cebc1f 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/get_all_locations.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/get_all_locations.ts @@ -5,7 +5,7 @@ * 2.0. */ import { SavedObjectsClientContract } from '@kbn/core/server'; -import { toClientContract } from '../routes/settings/private_locations/helpers'; +import { allLocationsToClientContract } from '../routes/settings/private_locations/helpers'; import { getPrivateLocationsAndAgentPolicies } from '../routes/settings/private_locations/get_private_locations'; import { SyntheticsServerSetup } from '../types'; import { getServiceLocations } from './get_service_locations'; @@ -34,7 +34,10 @@ export async function getAllLocations({ ), getServicePublicLocations(server, syntheticsMonitorClient), ]); - const pvtLocations = toClientContract({ locations: privateLocations }, agentPolicies); + const pvtLocations = allLocationsToClientContract( + { locations: privateLocations }, + agentPolicies + ); return { publicLocations, privateLocations: pvtLocations, diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/get_private_locations.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/get_private_locations.ts index a850cbf081e6..a476df9dfe03 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/get_private_locations.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/get_private_locations.ts @@ -5,22 +5,42 @@ * 2.0. */ -import { SavedObjectsClientContract, SavedObjectsErrorHelpers } from '@kbn/core/server'; import { - privateLocationsSavedObjectId, - privateLocationsSavedObjectName, + SavedObject, + SavedObjectsClientContract, + SavedObjectsErrorHelpers, +} from '@kbn/core/server'; +import { uniqBy } from 'lodash'; +import { + legacyPrivateLocationsSavedObjectId, + legacyPrivateLocationsSavedObjectName, + privateLocationSavedObjectName, } from '../../common/saved_objects/private_locations'; -import type { SyntheticsPrivateLocationsAttributes } from '../runtime_types/private_locations'; +import { + PrivateLocationAttributes, + SyntheticsPrivateLocationsAttributes, +} from '../runtime_types/private_locations'; export const getPrivateLocations = async ( client: SavedObjectsClientContract ): Promise => { try { - const obj = await client.get( - privateLocationsSavedObjectName, - privateLocationsSavedObjectId - ); - return obj?.attributes.locations ?? []; + const finder = client.createPointInTimeFinder({ + type: privateLocationSavedObjectName, + perPage: 1000, + }); + + const results: Array> = []; + + for await (const response of finder.find()) { + results.push(...response.saved_objects); + } + + finder.close().catch((e) => {}); + + const legacyLocations = await getLegacyPrivateLocations(client); + + return uniqBy([...results.map((r) => r.attributes), ...legacyLocations], 'id'); } catch (getErr) { if (SavedObjectsErrorHelpers.isNotFoundError(getErr)) { return []; @@ -28,3 +48,15 @@ export const getPrivateLocations = async ( throw getErr; } }; + +const getLegacyPrivateLocations = async (client: SavedObjectsClientContract) => { + try { + const obj = await client.get( + legacyPrivateLocationsSavedObjectName, + legacyPrivateLocationsSavedObjectId + ); + return obj?.attributes.locations ?? []; + } catch (getErr) { + return []; + } +}; diff --git a/x-pack/plugins/observability_solution/synthetics/tsconfig.json b/x-pack/plugins/observability_solution/synthetics/tsconfig.json index 5df6d4257b4e..267298a23427 100644 --- a/x-pack/plugins/observability_solution/synthetics/tsconfig.json +++ b/x-pack/plugins/observability_solution/synthetics/tsconfig.json @@ -18,7 +18,6 @@ "@kbn/observability-plugin", "@kbn/fleet-plugin", "@kbn/unified-search-plugin", - "@kbn/index-lifecycle-management-plugin", "@kbn/i18n", "@kbn/core", "@kbn/config-schema", @@ -105,7 +104,8 @@ "@kbn/slo-plugin", "@kbn/ebt-tools", "@kbn/alerting-types", - "@kbn/core-chrome-browser" + "@kbn/core-chrome-browser", + "@kbn/index-lifecycle-management-common-shared" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/observability_solution/uptime/.buildkite/pipelines/flaky.js b/x-pack/plugins/observability_solution/uptime/.buildkite/pipelines/flaky.js index 7a1ee5c582d7..ca024e9b4228 100644 --- a/x-pack/plugins/observability_solution/uptime/.buildkite/pipelines/flaky.js +++ b/x-pack/plugins/observability_solution/uptime/.buildkite/pipelines/flaky.js @@ -63,8 +63,8 @@ console.log(JSON.stringify(pipeline, null, 2)); function getBuildJob() { return { command: '.buildkite/scripts/steps/build_kibana.sh', - label: 'Build Kibana Distribution and Plugins', - agents: { queue: 'c2-8' }, + label: 'Build Kibana Distribution', + agents: { queue: 'n2-8' }, key: BUILD_UUID, if: `build.env('${KIBANA_BUILD_ID}') == null || build.env('${KIBANA_BUILD_ID}') == ''`, }; diff --git a/x-pack/plugins/observability_solution/ux/.buildkite/pipelines/flaky.js b/x-pack/plugins/observability_solution/ux/.buildkite/pipelines/flaky.js index 6a01e8c52d00..b9a1782820ae 100644 --- a/x-pack/plugins/observability_solution/ux/.buildkite/pipelines/flaky.js +++ b/x-pack/plugins/observability_solution/ux/.buildkite/pipelines/flaky.js @@ -64,8 +64,8 @@ console.log(JSON.stringify(pipeline, null, 2)); function getBuildJob() { return { command: '.buildkite/scripts/steps/build_kibana.sh', - label: 'Build Kibana Distribution and Plugins', - agents: { queue: 'c2-8' }, + label: 'Build Kibana Distribution', + agents: { queue: 'n2-8' }, key: BUILD_UUID, if: `build.env('${KIBANA_BUILD_ID}') == null || build.env('${KIBANA_BUILD_ID}') == ''`, }; diff --git a/x-pack/plugins/osquery/cypress/e2e/all/ecs_mappings.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/ecs_mappings.cy.ts index 4bafc3d17315..98db4ab75479 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/ecs_mappings.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/ecs_mappings.cy.ts @@ -18,7 +18,9 @@ import { typeInOsqueryFieldInput, } from '../../tasks/live_query'; -describe('EcsMapping', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/192128 +// Failing: See https://github.com/elastic/kibana/issues/192128 +describe.skip('EcsMapping', { tags: ['@ess', '@serverless', '@skipInServerlessMKI'] }, () => { beforeEach(() => { initializeDataViews(); }); diff --git a/x-pack/plugins/search_connectors/kibana.jsonc b/x-pack/plugins/search_connectors/kibana.jsonc index e5aac900e89c..83d052ac232a 100644 --- a/x-pack/plugins/search_connectors/kibana.jsonc +++ b/x-pack/plugins/search_connectors/kibana.jsonc @@ -2,6 +2,8 @@ "type": "plugin", "id": "@kbn/search-connectors-plugin", "owner": "@elastic/search-kibana", + "group": "platform", + "visibility": "shared", "description": "Plugin hosting shared features for connectors", "plugin": { "id": "searchConnectors", diff --git a/x-pack/plugins/search_homepage/kibana.jsonc b/x-pack/plugins/search_homepage/kibana.jsonc index 0e345ab0d330..7120432e1ef7 100644 --- a/x-pack/plugins/search_homepage/kibana.jsonc +++ b/x-pack/plugins/search_homepage/kibana.jsonc @@ -2,6 +2,8 @@ "type": "plugin", "id": "@kbn/search-homepage", "owner": "@elastic/search-kibana", + "group": "search", + "visibility": "private", "plugin": { "id": "searchHomepage", "server": true, diff --git a/x-pack/plugins/search_indices/kibana.jsonc b/x-pack/plugins/search_indices/kibana.jsonc index dee69b2b4e10..50778c3fbb4e 100644 --- a/x-pack/plugins/search_indices/kibana.jsonc +++ b/x-pack/plugins/search_indices/kibana.jsonc @@ -2,6 +2,8 @@ "type": "plugin", "id": "@kbn/search-indices", "owner": "@elastic/search-kibana", + "group": "search", + "visibility": "private", "plugin": { "id": "searchIndices", "server": true, @@ -25,4 +27,4 @@ "esUiShared" ] } -} \ No newline at end of file +} diff --git a/x-pack/plugins/search_indices/public/analytics/constants.ts b/x-pack/plugins/search_indices/public/analytics/constants.ts index d64019d6ef67..0da7aedf1932 100644 --- a/x-pack/plugins/search_indices/public/analytics/constants.ts +++ b/x-pack/plugins/search_indices/public/analytics/constants.ts @@ -12,9 +12,9 @@ export enum AnalyticsEvents { startCreateIndexPageModifyIndexName = 'start_modify_index_name', startCreateIndexClick = 'start_create_index', startCreateIndexLanguageSelect = 'start_code_lang_select', + startCreateIndexRunInConsole = 'start_cta_run_in_console', startCreateIndexCodeCopyInstall = 'start_code_copy_install', startCreateIndexCodeCopy = 'start_code_copy', - startCreateIndexRunInConsole = 'start_cta_run_in_console', startCreateIndexCreatedRedirect = 'start_index_created_api', startFileUploadClick = 'start_file_upload', indexDetailsInstallCodeCopy = 'index_details_code_copy_install', @@ -23,4 +23,15 @@ export enum AnalyticsEvents { indexDetailsNavDataTab = 'index_details_nav_data_tab', indexDetailsNavSettingsTab = 'index_details_nav_settings_tab', indexDetailsNavMappingsTab = 'index_details_nav_mappings_tab', + createIndexPageOpened = 'create_index_page_opened', + createIndexShowCodeClick = 'create_index_show_code', + createIndexShowUIClick = 'create_index_show_create_index_ui', + createIndexPageModifyIndexName = 'create_index_modify_index_name', + createIndexCreateIndexClick = 'create_index_click_create', + createIndexLanguageSelect = 'create_index_code_lang_select', + createIndexRunInConsole = 'create_index_run_in_console', + createIndexCodeCopyInstall = 'create_index_copy_install', + createIndexCodeCopy = 'create_index_code_copy', + createIndexFileUploadClick = 'create_index_file_upload', + createIndexIndexCreatedRedirect = 'create_index_created_api', } diff --git a/x-pack/plugins/search_indices/public/code_examples/sense.ts b/x-pack/plugins/search_indices/public/code_examples/sense.ts index 34e4e8180276..f54071003df6 100644 --- a/x-pack/plugins/search_indices/public/code_examples/sense.ts +++ b/x-pack/plugins/search_indices/public/code_examples/sense.ts @@ -36,7 +36,7 @@ export const ConsoleVectorsIngestDataExample: IngestDataCodeDefinition = { let result = 'POST /_bulk?pretty\n'; sampleDocuments.forEach((document) => { result += `{ "index": { "_index": "${indexName}" } } -${JSON.stringify(document)}`; +${JSON.stringify(document)}\n`; }); result += '\n'; return result; diff --git a/x-pack/plugins/search_indices/public/components/create_index/create_index.tsx b/x-pack/plugins/search_indices/public/components/create_index/create_index.tsx new file mode 100644 index 000000000000..d8ce8073c691 --- /dev/null +++ b/x-pack/plugins/search_indices/public/components/create_index/create_index.tsx @@ -0,0 +1,114 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useState } from 'react'; + +import type { IndicesStatusResponse, UserStartPrivilegesResponse } from '../../../common'; + +import { AnalyticsEvents } from '../../analytics/constants'; +import { AvailableLanguages } from '../../code_examples'; +import { useKibana } from '../../hooks/use_kibana'; +import { useUsageTracker } from '../../hooks/use_usage_tracker'; +import { CreateIndexFormState } from '../../types'; +import { generateRandomIndexName } from '../../utils/indices'; +import { getDefaultCodingLanguage } from '../../utils/language'; + +import { CreateIndexPanel } from '../shared/create_index_panel'; + +import { CreateIndexCodeView } from './create_index_code_view'; +import { CreateIndexUIView } from './create_index_ui_view'; + +function initCreateIndexState() { + const defaultIndexName = generateRandomIndexName(); + return { + indexName: defaultIndexName, + defaultIndexName, + codingLanguage: getDefaultCodingLanguage(), + }; +} + +export interface CreateIndexProps { + indicesData?: IndicesStatusResponse; + userPrivileges?: UserStartPrivilegesResponse; +} + +enum CreateIndexViewMode { + UI = 'ui', + Code = 'code', +} + +export const CreateIndex = ({ indicesData, userPrivileges }: CreateIndexProps) => { + const { application } = useKibana().services; + const [createIndexView, setCreateIndexView] = useState( + userPrivileges?.privileges.canCreateIndex === false + ? CreateIndexViewMode.Code + : CreateIndexViewMode.UI + ); + const [formState, setFormState] = useState(initCreateIndexState); + const usageTracker = useUsageTracker(); + const onChangeView = useCallback( + (id: string) => { + switch (id) { + case CreateIndexViewMode.UI: + usageTracker.click(AnalyticsEvents.createIndexShowUIClick); + setCreateIndexView(CreateIndexViewMode.UI); + return; + case CreateIndexViewMode.Code: + usageTracker.click(AnalyticsEvents.createIndexShowCodeClick); + setCreateIndexView(CreateIndexViewMode.Code); + return; + } + }, + [usageTracker] + ); + const onChangeCodingLanguage = useCallback( + (language: AvailableLanguages) => { + setFormState({ + ...formState, + codingLanguage: language, + }); + usageTracker.count([ + AnalyticsEvents.createIndexLanguageSelect, + `${AnalyticsEvents.createIndexLanguageSelect}_${language}`, + ]); + }, + [usageTracker, formState, setFormState] + ); + const onClose = useCallback(() => { + application.navigateToApp('management', { deepLinkId: 'index_management' }); + }, [application]); + + return ( + + {createIndexView === CreateIndexViewMode.UI && ( + + )} + {createIndexView === CreateIndexViewMode.Code && ( + + )} + + ); +}; diff --git a/x-pack/plugins/search_indices/public/components/create_index/create_index_code_view.tsx b/x-pack/plugins/search_indices/public/components/create_index/create_index_code_view.tsx new file mode 100644 index 000000000000..cdadfbdc146f --- /dev/null +++ b/x-pack/plugins/search_indices/public/components/create_index/create_index_code_view.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import type { IndicesStatusResponse } from '../../../common'; +import { + CreateIndexCodeView as SharedCreateIndexCodeView, + CreateIndexCodeViewProps as SharedCreateIndexCodeViewProps, +} from '../shared/create_index_code_view'; + +import { useIndicesRedirect } from './hooks/use_indices_redirect'; + +export interface CreateIndexCodeViewProps extends SharedCreateIndexCodeViewProps { + indicesData?: IndicesStatusResponse; +} + +export const CreateIndexCodeView = ({ indicesData, ...props }: CreateIndexCodeViewProps) => { + useIndicesRedirect(indicesData); + + return ; +}; diff --git a/x-pack/plugins/search_indices/public/components/create_index/create_index_page.tsx b/x-pack/plugins/search_indices/public/components/create_index/create_index_page.tsx new file mode 100644 index 000000000000..d8601e95760d --- /dev/null +++ b/x-pack/plugins/search_indices/public/components/create_index/create_index_page.tsx @@ -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 React, { useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { EuiLoadingLogo, EuiPageTemplate } from '@elastic/eui'; +import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; + +import { useKibana } from '../../hooks/use_kibana'; +import { useIndicesStatusQuery } from '../../hooks/api/use_indices_status'; +import { useUserPrivilegesQuery } from '../../hooks/api/use_user_permissions'; +import { LoadIndicesStatusError } from '../shared/load_indices_status_error'; + +import { CreateIndex } from './create_index'; +import { usePageChrome } from '../../hooks/use_page_chrome'; +import { IndexManagementBreadcrumbs } from '../shared/breadcrumbs'; + +const CreateIndexLabel = i18n.translate('xpack.searchIndices.createIndex.docTitle', { + defaultMessage: 'Create Index', +}); + +export const CreateIndexPage = () => { + const { console: consolePlugin } = useKibana().services; + const { + data: indicesData, + isInitialLoading, + isError: hasIndicesStatusFetchError, + error: indicesFetchError, + } = useIndicesStatusQuery(); + const { data: userPrivileges } = useUserPrivilegesQuery(); + + const embeddableConsole = useMemo( + () => (consolePlugin?.EmbeddableConsole ? : null), + [consolePlugin] + ); + usePageChrome(CreateIndexLabel, [...IndexManagementBreadcrumbs, { text: CreateIndexLabel }]); + + return ( + + + {isInitialLoading && } + {hasIndicesStatusFetchError && } + {!isInitialLoading && !hasIndicesStatusFetchError && ( + + )} + + {embeddableConsole} + + ); +}; diff --git a/x-pack/plugins/search_indices/public/components/create_index/create_index_ui_view.tsx b/x-pack/plugins/search_indices/public/components/create_index/create_index_ui_view.tsx new file mode 100644 index 000000000000..08073c0e8479 --- /dev/null +++ b/x-pack/plugins/search_indices/public/components/create_index/create_index_ui_view.tsx @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useState } from 'react'; + +import type { UserStartPrivilegesResponse } from '../../../common'; +import { AnalyticsEvents } from '../../analytics/constants'; +import { CreateIndexFormState } from '../../types'; +import { CreateIndexForm } from '../shared/create_index_form'; +import { useUsageTracker } from '../../hooks/use_usage_tracker'; +import { isValidIndexName } from '../../utils/indices'; +import { useCreateIndex } from '../shared/hooks/use_create_index'; + +import { useKibana } from '../../hooks/use_kibana'; + +export interface CreateIndexUIViewProps { + formState: CreateIndexFormState; + setFormState: (value: CreateIndexFormState) => void; + userPrivileges?: UserStartPrivilegesResponse; +} + +export const CreateIndexUIView = ({ + formState, + setFormState, + userPrivileges, +}: CreateIndexUIViewProps) => { + const [indexNameHasError, setIndexNameHasError] = useState(false); + const { application } = useKibana().services; + const usageTracker = useUsageTracker(); + const { createIndex, isLoading } = useCreateIndex(); + const onIndexNameChange = (e: React.ChangeEvent) => { + const newIndexName = e.target.value; + setFormState({ ...formState, indexName: e.target.value }); + const invalidIndexName = !isValidIndexName(newIndexName); + if (indexNameHasError !== invalidIndexName) { + setIndexNameHasError(invalidIndexName); + } + }; + const onCreateIndex = useCallback( + (e: React.FormEvent) => { + e.preventDefault(); + if (!isValidIndexName(formState.indexName)) { + return; + } + usageTracker.click(AnalyticsEvents.createIndexCreateIndexClick); + + if (formState.defaultIndexName !== formState.indexName) { + usageTracker.click(AnalyticsEvents.createIndexPageModifyIndexName); + } + + createIndex({ indexName: formState.indexName }); + }, + [usageTracker, createIndex, formState.indexName, formState.defaultIndexName] + ); + const onFileUpload = useCallback(() => { + usageTracker.click(AnalyticsEvents.createIndexFileUploadClick); + application.navigateToApp('ml', { path: 'filedatavisualizer' }); + }, [usageTracker, application]); + + return ( + + ); +}; diff --git a/x-pack/plugins/search_indices/public/components/create_index/hooks/use_indices_redirect.tsx b/x-pack/plugins/search_indices/public/components/create_index/hooks/use_indices_redirect.tsx new file mode 100644 index 000000000000..4246976209a9 --- /dev/null +++ b/x-pack/plugins/search_indices/public/components/create_index/hooks/use_indices_redirect.tsx @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEffect, useState } from 'react'; + +import type { IndicesStatusResponse } from '../../../../common'; + +import { useKibana } from '../../../hooks/use_kibana'; + +import { getFirstNewIndexName } from '../../../utils/indices'; +import { navigateToIndexDetails } from '../../utils'; +import { useUsageTracker } from '../../../contexts/usage_tracker_context'; +import { AnalyticsEvents } from '../../../analytics/constants'; + +export const useIndicesRedirect = (indicesStatus?: IndicesStatusResponse) => { + const { application, http } = useKibana().services; + const [initialStatus, setInitialStatus] = useState(undefined); + const [hasDoneRedirect, setHasDoneRedirect] = useState(() => false); + const usageTracker = useUsageTracker(); + return useEffect(() => { + if (hasDoneRedirect) { + return; + } + if (!indicesStatus) { + return; + } + if (initialStatus === undefined) { + setInitialStatus(indicesStatus); + return; + } + const newIndexName = getFirstNewIndexName(initialStatus.indexNames, indicesStatus.indexNames); + if (newIndexName) { + navigateToIndexDetails(application, http, newIndexName); + setHasDoneRedirect(true); + usageTracker.click(AnalyticsEvents.createIndexIndexCreatedRedirect); + return; + } + }, [ + application, + http, + indicesStatus, + initialStatus, + setHasDoneRedirect, + usageTracker, + hasDoneRedirect, + ]); +}; diff --git a/x-pack/plugins/search_indices/public/components/indices/details_page.tsx b/x-pack/plugins/search_indices/public/components/indices/details_page.tsx index ad5e174dd6e4..c672bb51493f 100644 --- a/x-pack/plugins/search_indices/public/components/indices/details_page.tsx +++ b/x-pack/plugins/search_indices/public/components/indices/details_page.tsx @@ -37,20 +37,14 @@ import { SearchIndexDetailsPageMenuItemPopover } from './details_page_menu_item' import { useIndexDocumentSearch } from '../../hooks/api/use_document_search'; import { useUsageTracker } from '../../contexts/usage_tracker_context'; import { AnalyticsEvents } from '../../analytics/constants'; +import { usePageChrome } from '../../hooks/use_page_chrome'; +import { IndexManagementBreadcrumbs } from '../shared/breadcrumbs'; export const SearchIndexDetailsPage = () => { const indexName = decodeURIComponent(useParams<{ indexName: string }>().indexName); const tabId = decodeURIComponent(useParams<{ tabId: string }>().tabId); - const { - console: consolePlugin, - docLinks, - application, - history, - share, - chrome, - serverless, - } = useKibana().services; + const { console: consolePlugin, docLinks, application, history, share } = useKibana().services; const { data: index, refetch, @@ -82,23 +76,12 @@ export const SearchIndexDetailsPage = () => { setHasDocuments(!(!isInitialLoading && indexDocuments?.results?.data.length === 0)); }, [indexDocuments, isInitialLoading, setHasDocuments, setDocumentsLoading]); - useEffect(() => { - chrome.docTitle.change(indexName); - - if (serverless) { - serverless.setBreadcrumbs([ - { - text: i18n.translate('xpack.searchIndices.indexBreadcrumbLabel', { - defaultMessage: 'Index Management', - }), - href: '/app/management/data/index_management/indices', - }, - { - text: indexName, - }, - ]); - } - }, [chrome, indexName, serverless]); + usePageChrome(indexName, [ + ...IndexManagementBreadcrumbs, + { + text: indexName, + }, + ]); const usageTracker = useUsageTracker(); diff --git a/x-pack/plugins/search_indices/public/components/indices/indices_router.tsx b/x-pack/plugins/search_indices/public/components/indices_router.tsx similarity index 80% rename from x-pack/plugins/search_indices/public/components/indices/indices_router.tsx rename to x-pack/plugins/search_indices/public/components/indices_router.tsx index 51527a7d2ef8..56ccb3c0674e 100644 --- a/x-pack/plugins/search_indices/public/components/indices/indices_router.tsx +++ b/x-pack/plugins/search_indices/public/components/indices_router.tsx @@ -7,13 +7,17 @@ import React from 'react'; import { Route, Router, Routes } from '@kbn/shared-ux-router'; import { Redirect } from 'react-router-dom'; -import { useKibana } from '../../hooks/use_kibana'; + +import { useKibana } from '../hooks/use_kibana'; import { SearchIndexDetailsTabs, SEARCH_INDICES_DETAILS_PATH, SEARCH_INDICES_DETAILS_TABS_PATH, -} from '../../routes'; -import { SearchIndexDetailsPage } from './details_page'; + CREATE_INDEX_PATH, +} from '../routes'; +import { SearchIndexDetailsPage } from './indices/details_page'; +import { CreateIndexPage } from './create_index/create_index_page'; + export const SearchIndicesRouter: React.FC = () => { const { application, history } = useKibana().services; return ( @@ -29,6 +33,7 @@ export const SearchIndicesRouter: React.FC = () => { /> + { application.navigateToApp('elasticsearchStart'); diff --git a/x-pack/plugins/search_indices/public/components/quick_stats/quick_stat.tsx b/x-pack/plugins/search_indices/public/components/quick_stats/quick_stat.tsx index 006906f8dd29..cdd5f1240848 100644 --- a/x-pack/plugins/search_indices/public/components/quick_stats/quick_stat.tsx +++ b/x-pack/plugins/search_indices/public/components/quick_stats/quick_stat.tsx @@ -70,7 +70,7 @@ export const QuickStat: React.FC = ({ marginRight: euiTheme.size.s, }, '.euiAccordion__triggerWrapper': { - background: euiTheme.colors.ghost, + background: euiTheme.colors.emptyShade, }, '.euiAccordion__children': { borderTop: euiTheme.border.thin, diff --git a/x-pack/plugins/search_indices/public/components/quick_stats/quick_stats.tsx b/x-pack/plugins/search_indices/public/components/quick_stats/quick_stats.tsx index 32590cf3efa4..e051fee17d2e 100644 --- a/x-pack/plugins/search_indices/public/components/quick_stats/quick_stats.tsx +++ b/x-pack/plugins/search_indices/public/components/quick_stats/quick_stats.tsx @@ -87,7 +87,7 @@ export const QuickStats: React.FC = ({ index, mappings, indexDo open={open} setOpen={setOpen} icon="documents" - iconColor="black" + iconColor={euiTheme.colors.fullShade} title={i18n.translate('xpack.searchIndices.quickStats.document_count_heading', { defaultMessage: 'Document count', })} @@ -115,7 +115,7 @@ export const QuickStats: React.FC = ({ index, mappings, indexDo open={open} setOpen={setOpen} icon="sparkles" - iconColor="black" + iconColor={euiTheme.colors.fullShade} title={i18n.translate('xpack.searchIndices.quickStats.ai_search_heading', { defaultMessage: 'AI Search', })} diff --git a/x-pack/plugins/search_indices/public/components/start/api_key_callout.tsx b/x-pack/plugins/search_indices/public/components/shared/api_key_callout.tsx similarity index 82% rename from x-pack/plugins/search_indices/public/components/start/api_key_callout.tsx rename to x-pack/plugins/search_indices/public/components/shared/api_key_callout.tsx index 65363e9f7322..1fe6c6d1a7ed 100644 --- a/x-pack/plugins/search_indices/public/components/start/api_key_callout.tsx +++ b/x-pack/plugins/search_indices/public/components/shared/api_key_callout.tsx @@ -17,19 +17,19 @@ interface APIKeyCalloutProps { export const APIKeyCallout = ({ apiKey }: APIKeyCalloutProps) => { const title = apiKey - ? i18n.translate('xpack.searchIndices.startPage.codeView.apiKeyTitle', { + ? i18n.translate('xpack.searchIndices.shared.codeView.apiKeyTitle', { defaultMessage: 'Copy your API key', }) - : i18n.translate('xpack.searchIndices.startPage.codeView.explicitGenerate.apiKeyTitle', { + : i18n.translate('xpack.searchIndices.shared.codeView.explicitGenerate.apiKeyTitle', { defaultMessage: 'Create an API key', }); const description = apiKey - ? i18n.translate('xpack.searchIndices.startPage.codeView.apiKeyDescription', { + ? i18n.translate('xpack.searchIndices.shared.codeView.apiKeyDescription', { defaultMessage: 'Make sure you keep it somewhere safe. You won’t be able to retrieve it later.', }) - : i18n.translate('xpack.searchIndices.startPage.codeView.explicitGenerate.apiKeyDescription', { + : i18n.translate('xpack.searchIndices.shared.codeView.explicitGenerate.apiKeyDescription', { defaultMessage: 'Create an API key to connect to Elasticsearch.', }); diff --git a/x-pack/plugins/search_indices/public/components/shared/breadcrumbs.ts b/x-pack/plugins/search_indices/public/components/shared/breadcrumbs.ts new file mode 100644 index 000000000000..2805100d6cab --- /dev/null +++ b/x-pack/plugins/search_indices/public/components/shared/breadcrumbs.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ChromeBreadcrumb } from '@kbn/core-chrome-browser'; +import { i18n } from '@kbn/i18n'; + +export const IndexManagementBreadcrumbs: ChromeBreadcrumb[] = [ + { + text: i18n.translate('xpack.searchIndices.breadcrumbs.indexManagement.label', { + defaultMessage: 'Index Management', + }), + href: '/app/management/data/index_management', + }, + { + text: i18n.translate('xpack.searchIndices.breadcrumbs.indexManagement.indices.label', { + defaultMessage: 'Indices', + }), + href: '/app/management/data/index_management/indices', + }, +]; diff --git a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx b/x-pack/plugins/search_indices/public/components/shared/create_index_code_view.tsx similarity index 67% rename from x-pack/plugins/search_indices/public/components/start/create_index_code.tsx rename to x-pack/plugins/search_indices/public/components/shared/create_index_code_view.tsx index fadfe1c7dcb9..14e9162fb970 100644 --- a/x-pack/plugins/search_indices/public/components/start/create_index_code.tsx +++ b/x-pack/plugins/search_indices/public/components/shared/create_index_code_view.tsx @@ -4,61 +4,55 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useCallback, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { TryInConsoleButton } from '@kbn/try-in-console'; import { useSearchApiKey } from '@kbn/search-api-keys-components'; -import { AnalyticsEvents } from '../../analytics/constants'; import { Languages, AvailableLanguages, LanguageOptions } from '../../code_examples'; import { useUsageTracker } from '../../hooks/use_usage_tracker'; import { useKibana } from '../../hooks/use_kibana'; import { useElasticsearchUrl } from '../../hooks/use_elasticsearch_url'; -import { CodeSample } from '../shared/code_sample'; -import { LanguageSelector } from '../shared/language_selector'; - -import { CreateIndexFormState } from './types'; -import { useStartPageCodingExamples } from './hooks/use_coding_examples'; import { APIKeyCallout } from './api_key_callout'; +import { CodeSample } from './code_sample'; +import { useCreateIndexCodingExamples } from './hooks/use_create_index_coding_examples'; +import { LanguageSelector } from './language_selector'; export interface CreateIndexCodeViewProps { - createIndexForm: CreateIndexFormState; + selectedLanguage: AvailableLanguages; + indexName: string; changeCodingLanguage: (language: AvailableLanguages) => void; canCreateApiKey?: boolean; + analyticsEvents: { + runInConsole: string; + installCommands: string; + createIndex: string; + }; } export const CreateIndexCodeView = ({ - createIndexForm, - changeCodingLanguage, + analyticsEvents, canCreateApiKey, + changeCodingLanguage, + indexName, + selectedLanguage, }: CreateIndexCodeViewProps) => { const { application, share, console: consolePlugin } = useKibana().services; const usageTracker = useUsageTracker(); - const selectedCodeExamples = useStartPageCodingExamples(); + const selectedCodeExamples = useCreateIndexCodingExamples(); - const { codingLanguage: selectedLanguage } = createIndexForm; - const onSelectLanguage = useCallback( - (value: AvailableLanguages) => { - changeCodingLanguage(value); - usageTracker.count([ - AnalyticsEvents.startCreateIndexLanguageSelect, - `${AnalyticsEvents.startCreateIndexLanguageSelect}_${value}`, - ]); - }, - [usageTracker, changeCodingLanguage] - ); const elasticsearchUrl = useElasticsearchUrl(); const { apiKey, apiKeyIsVisible } = useSearchApiKey(); const codeParams = useMemo(() => { return { - indexName: createIndexForm.indexName || undefined, + indexName: indexName || undefined, elasticsearchURL: elasticsearchUrl, apiKey: apiKeyIsVisible && apiKey ? apiKey : undefined, }; - }, [createIndexForm.indexName, elasticsearchUrl, apiKeyIsVisible, apiKey]); + }, [indexName, elasticsearchUrl, apiKeyIsVisible, apiKey]); const selectedCodeExample = useMemo(() => { return selectedCodeExamples[selectedLanguage]; }, [selectedLanguage, selectedCodeExamples]); @@ -75,7 +69,7 @@ export const CreateIndexCodeView = ({ @@ -87,8 +81,8 @@ export const CreateIndexCodeView = ({ telemetryId={`${selectedLanguage}_create_index`} onClick={() => { usageTracker.click([ - AnalyticsEvents.startCreateIndexRunInConsole, - `${AnalyticsEvents.startCreateIndexRunInConsole}_${selectedLanguage}`, + analyticsEvents.runInConsole, + `${analyticsEvents.runInConsole}_${selectedLanguage}`, ]); }} /> @@ -102,8 +96,8 @@ export const CreateIndexCodeView = ({ code={selectedCodeExample.installCommand} onCodeCopyClick={() => { usageTracker.click([ - AnalyticsEvents.startCreateIndexCodeCopyInstall, - `${AnalyticsEvents.startCreateIndexCodeCopyInstall}_${selectedLanguage}`, + analyticsEvents.installCommands, + `${analyticsEvents.installCommands}_${selectedLanguage}`, ]); }} /> @@ -116,9 +110,9 @@ export const CreateIndexCodeView = ({ code={selectedCodeExample.createIndex(codeParams)} onCodeCopyClick={() => { usageTracker.click([ - AnalyticsEvents.startCreateIndexCodeCopy, - `${AnalyticsEvents.startCreateIndexCodeCopy}_${selectedLanguage}`, - `${AnalyticsEvents.startCreateIndexCodeCopy}_${selectedLanguage}_${selectedCodeExamples.exampleType}`, + analyticsEvents.createIndex, + `${analyticsEvents.createIndex}_${selectedLanguage}`, + `${analyticsEvents.createIndex}_${selectedLanguage}_${selectedCodeExamples.exampleType}`, ]); }} /> diff --git a/x-pack/plugins/search_indices/public/components/shared/create_index_form.tsx b/x-pack/plugins/search_indices/public/components/shared/create_index_form.tsx new file mode 100644 index 000000000000..ba2f83cb273d --- /dev/null +++ b/x-pack/plugins/search_indices/public/components/shared/create_index_form.tsx @@ -0,0 +1,165 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { + EuiButton, + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiForm, + EuiFormRow, + EuiHorizontalRule, + EuiIcon, + EuiLink, + EuiPanel, + EuiSpacer, + EuiText, + EuiToolTip, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import type { UserStartPrivilegesResponse } from '../../../common'; + +export interface CreateIndexFormProps { + indexName: string; + indexNameHasError: boolean; + isLoading: boolean; + onCreateIndex: (e: React.FormEvent) => void; + onFileUpload: () => void; + onIndexNameChange: (e: React.ChangeEvent) => void; + showAPIKeyCreateLabel: boolean; + userPrivileges?: UserStartPrivilegesResponse; +} + +export const CreateIndexForm = ({ + indexName, + indexNameHasError, + isLoading, + onCreateIndex, + onFileUpload, + onIndexNameChange, + showAPIKeyCreateLabel, + userPrivileges, +}: CreateIndexFormProps) => { + return ( + <> + + + + + + + + + {i18n.translate('xpack.searchIndices.shared.createIndex.permissionTooltip', { + defaultMessage: 'You do not have permission to create an index.', + })} +

    + ) : undefined + } + > + + {i18n.translate('xpack.searchIndices.shared.createIndex.action.text', { + defaultMessage: 'Create my index', + })} + +
    +
    + + {showAPIKeyCreateLabel && ( + + + +

    + {i18n.translate( + 'xpack.searchIndices.shared.createIndex.apiKeyCreation.description', + { + defaultMessage: "We'll create an API key for this index", + } + )} +

    +
    +
    + )} +
    +
    +
    + + + + + + + + +

    + + {i18n.translate('xpack.searchIndices.shared.createIndex.fileUpload.link', { + defaultMessage: 'Upload a file', + })} + + ), + }} + /> +

    +
    +
    +
    +
    + + ); +}; diff --git a/x-pack/plugins/search_indices/public/components/shared/create_index_panel.tsx b/x-pack/plugins/search_indices/public/components/shared/create_index_panel.tsx new file mode 100644 index 000000000000..8c353ebab6bd --- /dev/null +++ b/x-pack/plugins/search_indices/public/components/shared/create_index_panel.tsx @@ -0,0 +1,271 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import { + EuiButtonEmpty, + EuiButtonGroup, + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiPanel, + EuiSpacer, + EuiText, + EuiTextAlign, + EuiTitle, + useEuiTheme, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { docLinks } from '../../../common/doc_links'; +import { useKibana } from '../../hooks/use_kibana'; +import { CreateIndexViewMode } from '../../types'; + +const MAX_WIDTH = '650px'; + +export interface CreateIndexPanelProps { + children: React.ReactNode | React.ReactNode[]; + createIndexView: CreateIndexViewMode; + onChangeView: (id: string) => void; + onClose: () => void; + showCallouts?: boolean; + showSkip?: boolean; + title?: React.ReactNode; +} + +export const CreateIndexPanel = ({ + children, + createIndexView, + onChangeView, + onClose, + showCallouts, + showSkip, + title, +}: CreateIndexPanelProps) => { + const { cloud, http } = useKibana().services; + const { euiTheme } = useEuiTheme(); + + const o11yTrialLink = useMemo(() => { + if (cloud && cloud.isServerlessEnabled) { + const baseUrl = cloud?.projectsUrl ?? 'https://cloud.elastic.co/projects/'; + return `${baseUrl}create/observability/start`; + } + return http.basePath.prepend('/app/observability/onboarding'); + }, [cloud, http]); + + return ( + <> + + + + + + + + + + + +

    + {i18n.translate('xpack.searchIndices.shared.createIndex.pageTitle', { + defaultMessage: 'Elasticsearch', + })} +

    +
    +
    +
    + + +

    + {i18n.translate('xpack.searchIndices.shared.createIndex.pageDescription', { + defaultMessage: 'Get started with Elasticsearch', + })} +

    +
    +
    + + + + + + +

    + {title ?? + i18n.translate('xpack.searchIndices.shared.createIndex.defaultTitle', { + defaultMessage: 'Create an index', + })} +

    +
    +
    + + + +
    + +

    + {i18n.translate('xpack.searchIndices.shared.createIndex.description', { + defaultMessage: + 'An index stores your data and defines the schema, or field mappings, for your searches', + })} +

    +
    + {children} +
    +
    + {showCallouts && ( + <> + + + + +
    + {i18n.translate( + 'xpack.searchIndices.shared.createIndex.observabilityCallout.title', + { + defaultMessage: 'Looking to store your logs or metrics data?', + } + )} +
    +
    +
    + + + + + {i18n.translate( + 'xpack.searchIndices.shared.createIndex.observabilityCallout.logs.button', + { + defaultMessage: 'Collect and analyze logs', + } + )} + + + + {i18n.translate( + 'xpack.searchIndices.shared.createIndex.observabilityCallout.logs.subTitle', + { + defaultMessage: 'Explore Logstash and Beats', + } + )} + + + + + or + + + + {i18n.translate( + 'xpack.searchIndices.shared.createIndex.observabilityCallout.o11yTrial.button', + { + defaultMessage: 'Start an Observability trial', + } + )} + + + + {i18n.translate( + 'xpack.searchIndices.shared.createIndex.observabilityCallout.o11yTrial.subTitle', + { + defaultMessage: 'Powerful performance monitoring', + } + )} + + + + +
    + + )} +
    + {showSkip === true && ( + <> + + + + {i18n.translate('xpack.searchIndices.shared.createIndex.skipLabel', { + defaultMessage: 'Skip', + })} + + + + )} + + ); +}; diff --git a/x-pack/plugins/search_indices/public/components/start/hooks/use_create_index.tsx b/x-pack/plugins/search_indices/public/components/shared/hooks/use_create_index.tsx similarity index 94% rename from x-pack/plugins/search_indices/public/components/start/hooks/use_create_index.tsx rename to x-pack/plugins/search_indices/public/components/shared/hooks/use_create_index.tsx index 8daafec5573c..537aa3cc4b98 100644 --- a/x-pack/plugins/search_indices/public/components/start/hooks/use_create_index.tsx +++ b/x-pack/plugins/search_indices/public/components/shared/hooks/use_create_index.tsx @@ -11,7 +11,7 @@ import { useCreateIndex as useCreateIndexApi } from '../../../hooks/api/use_crea import { useKibana } from '../../../hooks/use_kibana'; -import { navigateToIndexDetails } from './utils'; +import { navigateToIndexDetails } from '../../utils'; export const useCreateIndex = () => { const { application, http } = useKibana().services; diff --git a/x-pack/plugins/search_indices/public/components/start/hooks/use_coding_examples.tsx b/x-pack/plugins/search_indices/public/components/shared/hooks/use_create_index_coding_examples.tsx similarity index 87% rename from x-pack/plugins/search_indices/public/components/start/hooks/use_coding_examples.tsx rename to x-pack/plugins/search_indices/public/components/shared/hooks/use_create_index_coding_examples.tsx index 1a351d10943f..fb1cb6a7eab5 100644 --- a/x-pack/plugins/search_indices/public/components/start/hooks/use_coding_examples.tsx +++ b/x-pack/plugins/search_indices/public/components/shared/hooks/use_create_index_coding_examples.tsx @@ -8,7 +8,7 @@ import { CreateIndexCodeExamples } from '../../../types'; import { DenseVectorSeverlessCodeExamples } from '../../../code_examples/create_index'; -export const useStartPageCodingExamples = (): CreateIndexCodeExamples => { +export const useCreateIndexCodingExamples = (): CreateIndexCodeExamples => { // TODO: in the future this will be dynamic based on the onboarding token // or project sub-type return DenseVectorSeverlessCodeExamples; diff --git a/x-pack/plugins/search_indices/public/components/start/status_error.tsx b/x-pack/plugins/search_indices/public/components/shared/load_indices_status_error.tsx similarity index 79% rename from x-pack/plugins/search_indices/public/components/start/status_error.tsx rename to x-pack/plugins/search_indices/public/components/shared/load_indices_status_error.tsx index 7e41e37d5cd9..58e1867cc577 100644 --- a/x-pack/plugins/search_indices/public/components/start/status_error.tsx +++ b/x-pack/plugins/search_indices/public/components/shared/load_indices_status_error.tsx @@ -15,14 +15,14 @@ export interface StartPageErrorProps { error: unknown; } -export const StartPageError = ({ error }: StartPageErrorProps) => { +export const LoadIndicesStatusError = ({ error }: StartPageErrorProps) => { return ( - {i18n.translate('xpack.searchIndices.startPage.statusFetchError.title', { + {i18n.translate('xpack.searchIndices.shared.statusFetchError.title', { defaultMessage: 'Error loading indices', })}

    @@ -31,7 +31,7 @@ export const StartPageError = ({ error }: StartPageErrorProps) => { {getErrorMessage( error, - i18n.translate('xpack.searchIndices.startPage.statusFetchError.unknownError', { + i18n.translate('xpack.searchIndices.shared.statusFetchError.unknownError', { defaultMessage: 'Unknown error fetching indices.', }) )} diff --git a/x-pack/plugins/search_indices/public/components/start/create_index.tsx b/x-pack/plugins/search_indices/public/components/start/create_index.tsx index 788bd1e36f2e..e7ca978fb8ea 100644 --- a/x-pack/plugins/search_indices/public/components/start/create_index.tsx +++ b/x-pack/plugins/search_indices/public/components/start/create_index.tsx @@ -6,52 +6,29 @@ */ import React, { useCallback, useState } from 'react'; -import { - EuiButton, - EuiFieldText, - EuiFlexGroup, - EuiFlexItem, - EuiForm, - EuiFormRow, - EuiHorizontalRule, - EuiIcon, - EuiLink, - EuiPanel, - EuiSpacer, - EuiText, - EuiToolTip, -} from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; import type { UserStartPrivilegesResponse } from '../../../common'; import { AnalyticsEvents } from '../../analytics/constants'; import { useUsageTracker } from '../../hooks/use_usage_tracker'; +import { CreateIndexFormState } from '../../types'; import { isValidIndexName } from '../../utils/indices'; -import { useCreateIndex } from './hooks/use_create_index'; +import { useCreateIndex } from '../shared/hooks/use_create_index'; +import { CreateIndexForm } from '../shared/create_index_form'; -import { CreateIndexFormState } from './types'; import { useKibana } from '../../hooks/use_kibana'; -const CREATE_INDEX_CONTENT = i18n.translate( - 'xpack.searchIndices.startPage.createIndex.action.text', - { - defaultMessage: 'Create my index', - } -); - -export interface CreateIndexFormProps { +export interface CreateIndexUIViewProps { formState: CreateIndexFormState; setFormState: React.Dispatch>; userPrivileges?: UserStartPrivilegesResponse; } -export const CreateIndexForm = ({ +export const CreateIndexUIView = ({ userPrivileges, formState, setFormState, -}: CreateIndexFormProps) => { +}: CreateIndexUIViewProps) => { const { application } = useKibana().services; const [indexNameHasError, setIndexNameHasError] = useState(false); const usageTracker = useUsageTracker(); @@ -86,129 +63,15 @@ export const CreateIndexForm = ({ }, [usageTracker, application]); return ( - <> - - - - - - - - {userPrivileges?.privileges?.canCreateIndex === false ? ( - - {i18n.translate('xpack.searchIndices.startPage.createIndex.permissionTooltip', { - defaultMessage: 'You do not have permission to create an index.', - })} -

    - } - > - - {CREATE_INDEX_CONTENT} - -
    - ) : ( - - {CREATE_INDEX_CONTENT} - - )} -
    - - {userPrivileges?.privileges?.canCreateApiKeys && ( - - - -

    - {i18n.translate( - 'xpack.searchIndices.startPage.createIndex.apiKeyCreation.description', - { - defaultMessage: "We'll create an API key for this index", - } - )} -

    -
    -
    - )} -
    -
    -
    - - - - - - - - -

    - - {i18n.translate( - 'xpack.searchIndices.startPage.createIndex.fileUpload.link', - { - defaultMessage: 'Upload a file', - } - )} - - ), - }} - /> -

    -
    -
    -
    -
    - + ); }; diff --git a/x-pack/plugins/search_indices/public/components/start/elasticsearch_start.tsx b/x-pack/plugins/search_indices/public/components/start/elasticsearch_start.tsx index 42b021043cb3..3f3063ddb150 100644 --- a/x-pack/plugins/search_indices/public/components/start/elasticsearch_start.tsx +++ b/x-pack/plugins/search_indices/public/components/start/elasticsearch_start.tsx @@ -5,23 +5,10 @@ * 2.0. */ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { - EuiButtonEmpty, - EuiButtonGroup, - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiPanel, - EuiSpacer, - EuiText, - EuiTextAlign, - EuiTitle, -} from '@elastic/eui'; +import React, { useCallback, useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; import type { IndicesStatusResponse, UserStartPrivilegesResponse } from '../../../common'; -import { docLinks } from '../../../common/doc_links'; import { AnalyticsEvents } from '../../analytics/constants'; import { AvailableLanguages } from '../../code_examples'; @@ -29,9 +16,11 @@ import { useUsageTracker } from '../../hooks/use_usage_tracker'; import { generateRandomIndexName } from '../../utils/indices'; import { getDefaultCodingLanguage } from '../../utils/language'; -import { CreateIndexForm } from './create_index'; -import { CreateIndexCodeView } from './create_index_code'; -import { CreateIndexFormState } from './types'; +import { CreateIndexUIView } from './create_index'; +import { CreateIndexCodeView } from '../shared/create_index_code_view'; +import { CreateIndexFormState, CreateIndexViewMode } from '../../types'; + +import { CreateIndexPanel } from '../shared/create_index_panel'; import { useKibana } from '../../hooks/use_kibana'; function initCreateIndexState(): CreateIndexFormState { @@ -43,21 +32,17 @@ function initCreateIndexState(): CreateIndexFormState { }; } -const MAX_WIDTH = '650px'; - -enum CreateIndexView { - UI = 'ui', - Code = 'code', -} export interface ElasticsearchStartProps { indicesData?: IndicesStatusResponse; userPrivileges?: UserStartPrivilegesResponse; } export const ElasticsearchStart = ({ userPrivileges }: ElasticsearchStartProps) => { - const { cloud, http } = useKibana().services; - const [createIndexView, setCreateIndexView] = useState( - userPrivileges?.privileges.canCreateIndex === false ? CreateIndexView.Code : CreateIndexView.UI + const { application } = useKibana().services; + const [createIndexView, setCreateIndexViewMode] = useState( + userPrivileges?.privileges.canCreateIndex === false + ? CreateIndexViewMode.Code + : CreateIndexViewMode.UI ); const [formState, setFormState] = useState(initCreateIndexState); const usageTracker = useUsageTracker(); @@ -68,28 +53,20 @@ export const ElasticsearchStart = ({ userPrivileges }: ElasticsearchStartProps) useEffect(() => { if (userPrivileges === undefined) return; if (userPrivileges.privileges.canCreateIndex === false) { - setCreateIndexView(CreateIndexView.Code); + setCreateIndexViewMode(CreateIndexViewMode.Code); } }, [userPrivileges]); - const o11yTrialLink = useMemo(() => { - if (cloud && cloud.isServerlessEnabled) { - const baseUrl = cloud?.projectsUrl ?? 'https://cloud.elastic.co/projects/'; - return `${baseUrl}create/observability/start`; - } - return http.basePath.prepend('/app/observability/onboarding'); - }, [cloud, http]); - const onChangeView = useCallback( (id: string) => { switch (id) { - case CreateIndexView.UI: + case CreateIndexViewMode.UI: usageTracker.click(AnalyticsEvents.startPageShowCreateIndexUIClick); - setCreateIndexView(CreateIndexView.UI); + setCreateIndexViewMode(CreateIndexViewMode.UI); return; - case CreateIndexView.Code: + case CreateIndexViewMode.Code: usageTracker.click(AnalyticsEvents.startPageShowCodeClick); - setCreateIndexView(CreateIndexView.Code); + setCreateIndexViewMode(CreateIndexViewMode.Code); return; } }, @@ -101,178 +78,48 @@ export const ElasticsearchStart = ({ userPrivileges }: ElasticsearchStartProps) ...formState, codingLanguage: language, }); + usageTracker.count([ + AnalyticsEvents.startCreateIndexLanguageSelect, + `${AnalyticsEvents.startCreateIndexLanguageSelect}_${language}`, + ]); }, - [formState, setFormState] + [usageTracker, formState, setFormState] ); + const onClose = useCallback(() => { + application.navigateToApp('management', { deepLinkId: 'index_management' }); + }, [application]); return ( - - - - - - - - -

    - {i18n.translate('xpack.searchIndices.startPage.pageTitle', { - defaultMessage: 'Elasticsearch', - })} -

    -
    -
    -
    - - -

    - {i18n.translate('xpack.searchIndices.startPage.pageDescription', { - defaultMessage: 'Vectorize, search, and visualize your data', - })} -

    -
    -
    - - - - - - -

    - {i18n.translate('xpack.searchIndices.startPage.createIndex.title', { - defaultMessage: 'Create your first index', - })} -

    -
    -
    - - - -
    - -

    - {i18n.translate('xpack.searchIndices.startPage.createIndex.description', { - defaultMessage: - 'An index stores your data and defines the schema, or field mappings, for your searches', - })} -

    -
    - {createIndexView === CreateIndexView.UI && ( - - )} - {createIndexView === CreateIndexView.Code && ( - - )} -
    -
    - - - - -
    - {i18n.translate('xpack.searchIndices.startPage.observabilityCallout.title', { - defaultMessage: 'Looking to store your logs or metrics data?', - })} -
    -
    -
    - - - - - {i18n.translate('xpack.searchIndices.startPage.observabilityCallout.logs.button', { - defaultMessage: 'Collect and analyze logs', - })} - - - - {i18n.translate( - 'xpack.searchIndices.startPage.observabilityCallout.logs.subTitle', - { - defaultMessage: 'Explore Logstash and Beats', - } - )} - - - - - or - - - - {i18n.translate( - 'xpack.searchIndices.startPage.observabilityCallout.o11yTrial.button', - { - defaultMessage: 'Start an Observability trial', - } - )} - - - - {i18n.translate( - 'xpack.searchIndices.startPage.observabilityCallout.o11yTrial.subTitle', - { - defaultMessage: 'Powerful performance monitoring', - } - )} - - - - -
    -
    + {createIndexView === CreateIndexViewMode.UI && ( + + )} + {createIndexView === CreateIndexViewMode.Code && ( + + )} + ); }; diff --git a/x-pack/plugins/search_indices/public/components/start/hooks/use_indices_redirect.tsx b/x-pack/plugins/search_indices/public/components/start/hooks/use_indices_redirect.tsx index 899d44da2afa..6909b1117e32 100644 --- a/x-pack/plugins/search_indices/public/components/start/hooks/use_indices_redirect.tsx +++ b/x-pack/plugins/search_indices/public/components/start/hooks/use_indices_redirect.tsx @@ -11,7 +11,7 @@ import type { IndicesStatusResponse } from '../../../../common'; import { useKibana } from '../../../hooks/use_kibana'; -import { navigateToIndexDetails } from './utils'; +import { navigateToIndexDetails } from '../../utils'; import { useUsageTracker } from '../../../contexts/usage_tracker_context'; import { AnalyticsEvents } from '../../../analytics/constants'; diff --git a/x-pack/plugins/search_indices/public/components/start/start_page.tsx b/x-pack/plugins/search_indices/public/components/start/start_page.tsx index 4a848f580d22..4dabec2e5fa9 100644 --- a/x-pack/plugins/search_indices/public/components/start/start_page.tsx +++ b/x-pack/plugins/search_indices/public/components/start/start_page.tsx @@ -6,6 +6,7 @@ */ import React, { useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; import { EuiLoadingLogo, EuiPageTemplate } from '@elastic/eui'; import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; @@ -16,7 +17,13 @@ import { useUserPrivilegesQuery } from '../../hooks/api/use_user_permissions'; import { useIndicesRedirect } from './hooks/use_indices_redirect'; import { ElasticsearchStart } from './elasticsearch_start'; -import { StartPageError } from './status_error'; +import { LoadIndicesStatusError } from '../shared/load_indices_status_error'; +import { IndexManagementBreadcrumbs } from '../shared/breadcrumbs'; +import { usePageChrome } from '../../hooks/use_page_chrome'; + +const PageTitle = i18n.translate('xpack.searchIndices.startPage.docTitle', { + defaultMessage: 'Create your first index', +}); export const ElasticsearchStartPage = () => { const { console: consolePlugin } = useKibana().services; @@ -27,6 +34,7 @@ export const ElasticsearchStartPage = () => { error: indicesFetchError, } = useIndicesStatusQuery(); const { data: userPrivileges } = useUserPrivilegesQuery(); + usePageChrome(PageTitle, [...IndexManagementBreadcrumbs, { text: PageTitle }]); const embeddableConsole = useMemo( () => (consolePlugin?.EmbeddableConsole ? : null), @@ -43,7 +51,7 @@ export const ElasticsearchStartPage = () => { > {isInitialLoading && } - {hasIndicesStatusFetchError && } + {hasIndicesStatusFetchError && } {!isInitialLoading && !hasIndicesStatusFetchError && ( )} diff --git a/x-pack/plugins/search_indices/public/components/start/hooks/utils.ts b/x-pack/plugins/search_indices/public/components/utils.ts similarity index 66% rename from x-pack/plugins/search_indices/public/components/start/hooks/utils.ts rename to x-pack/plugins/search_indices/public/components/utils.ts index ed8b6f40e51f..235c03b9faab 100644 --- a/x-pack/plugins/search_indices/public/components/start/hooks/utils.ts +++ b/x-pack/plugins/search_indices/public/components/utils.ts @@ -5,12 +5,15 @@ * 2.0. */ +import { generatePath } from 'react-router-dom'; + import type { ApplicationStart, HttpSetup } from '@kbn/core/public'; +import { INDICES_APP_BASE, SEARCH_INDICES_DETAILS_PATH } from '../routes'; -const INDEX_DETAILS_PATH = '/app/elasticsearch/indices/index_details'; +const INDEX_DETAILS_FULL_PATH = `${INDICES_APP_BASE}${SEARCH_INDICES_DETAILS_PATH}`; function getIndexDetailsPath(http: HttpSetup, indexName: string) { - return http.basePath.prepend(`${INDEX_DETAILS_PATH}/${encodeURIComponent(indexName)}`); + return http.basePath.prepend(generatePath(INDEX_DETAILS_FULL_PATH, { indexName })); } export const navigateToIndexDetails = ( diff --git a/x-pack/plugins/search_indices/public/hooks/use_page_chrome.ts b/x-pack/plugins/search_indices/public/hooks/use_page_chrome.ts new file mode 100644 index 000000000000..fae438b502a0 --- /dev/null +++ b/x-pack/plugins/search_indices/public/hooks/use_page_chrome.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 { useEffect } from 'react'; +import type { ChromeBreadcrumb } from '@kbn/core-chrome-browser'; +import { useKibana } from './use_kibana'; + +export const usePageChrome = (docTitle: string, breadcrumbs: ChromeBreadcrumb[]) => { + const { chrome, http, serverless } = useKibana().services; + + useEffect(() => { + chrome.docTitle.change(docTitle); + const newBreadcrumbs = breadcrumbs.map((breadcrumb) => { + if (breadcrumb.href && http.basePath.get().length > 0) { + breadcrumb.href = http.basePath.prepend(breadcrumb.href); + } + return breadcrumb; + }); + if (serverless) { + serverless.setBreadcrumbs(newBreadcrumbs); + } else { + chrome.setBreadcrumbs(newBreadcrumbs); + } + return () => { + // clear manually set breadcrumbs + if (serverless) { + serverless.setBreadcrumbs([]); + } else { + chrome.setBreadcrumbs([]); + } + }; + }, [breadcrumbs, chrome, docTitle, http.basePath, serverless]); +}; diff --git a/x-pack/plugins/search_indices/public/locators.ts b/x-pack/plugins/search_indices/public/locators.ts new file mode 100644 index 000000000000..587ce51f2c82 --- /dev/null +++ b/x-pack/plugins/search_indices/public/locators.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { LocatorDefinition } from '@kbn/share-plugin/common'; +import type { SharePluginSetup } from '@kbn/share-plugin/public'; +import type { SerializableRecord } from '@kbn/utility-types'; + +import { INDICES_APP_ID } from '../common'; +import { CREATE_INDEX_PATH } from './routes'; + +export function registerLocators(share: SharePluginSetup) { + share.url.locators.create(new CreateIndexLocatorDefinition()); +} + +class CreateIndexLocatorDefinition implements LocatorDefinition { + public readonly getLocation = async () => { + return { + app: INDICES_APP_ID, + path: CREATE_INDEX_PATH, + state: {}, + }; + }; + + public readonly id = 'SEARCH_CREATE_INDEX'; +} diff --git a/x-pack/plugins/search_indices/public/plugin.ts b/x-pack/plugins/search_indices/public/plugin.ts index c9b5c8f4c765..b92fbaa5e7f4 100644 --- a/x-pack/plugins/search_indices/public/plugin.ts +++ b/x-pack/plugins/search_indices/public/plugin.ts @@ -6,10 +6,12 @@ */ import type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import { SEARCH_INDICES_CREATE_INDEX } from '@kbn/deeplinks-search/constants'; import { i18n } from '@kbn/i18n'; import { docLinks } from '../common/doc_links'; import type { + AppPluginSetupDependencies, SearchIndicesAppPluginStartDependencies, SearchIndicesPluginSetup, SearchIndicesPluginStart, @@ -17,7 +19,13 @@ import type { } from './types'; import { initQueryClient } from './services/query_client'; import { INDICES_APP_ID, START_APP_ID } from '../common'; -import { INDICES_APP_BASE, START_APP_BASE, SearchIndexDetailsTabValues } from './routes'; +import { + CREATE_INDEX_PATH, + INDICES_APP_BASE, + START_APP_BASE, + SearchIndexDetailsTabValues, +} from './routes'; +import { registerLocators } from './locators'; export class SearchIndicesPlugin implements Plugin @@ -25,7 +33,8 @@ export class SearchIndicesPlugin private pluginEnabled: boolean = false; public setup( - core: CoreSetup + core: CoreSetup, + plugins: AppPluginSetupDependencies ): SearchIndicesPluginSetup { this.pluginEnabled = true; @@ -51,12 +60,21 @@ export class SearchIndicesPlugin core.application.register({ id: INDICES_APP_ID, appRoute: INDICES_APP_BASE, + deepLinks: [ + { + id: SEARCH_INDICES_CREATE_INDEX, + path: CREATE_INDEX_PATH, + title: i18n.translate('xpack.searchIndices.elasticsearchIndices.createIndexTitle', { + defaultMessage: 'Create index', + }), + }, + ], title: i18n.translate('xpack.searchIndices.elasticsearchIndices.startAppTitle', { defaultMessage: 'Elasticsearch Indices', }), async mount({ element, history }) { const { renderApp } = await import('./application'); - const { SearchIndicesRouter } = await import('./components/indices/indices_router'); + const { SearchIndicesRouter } = await import('./components/indices_router'); const [coreStart, depsStart] = await core.getStartServices(); const startDeps: SearchIndicesServicesContextDeps = { ...depsStart, @@ -66,6 +84,8 @@ export class SearchIndicesPlugin }, }); + registerLocators(plugins.share); + return { enabled: true, startAppId: START_APP_ID, diff --git a/x-pack/plugins/search_indices/public/routes.ts b/x-pack/plugins/search_indices/public/routes.ts index 057891d63226..86d05fb73032 100644 --- a/x-pack/plugins/search_indices/public/routes.ts +++ b/x-pack/plugins/search_indices/public/routes.ts @@ -13,6 +13,7 @@ export enum SearchIndexDetailsTabs { MAPPINGS = 'mappings', SETTINGS = 'settings', } +export const CREATE_INDEX_PATH = `${ROOT_PATH}create`; export const SearchIndexDetailsTabValues: string[] = Object.values(SearchIndexDetailsTabs); export const START_APP_BASE = '/app/elasticsearch/start'; diff --git a/x-pack/plugins/search_indices/public/types.ts b/x-pack/plugins/search_indices/public/types.ts index cfc732adff45..ccf4d56e13a6 100644 --- a/x-pack/plugins/search_indices/public/types.ts +++ b/x-pack/plugins/search_indices/public/types.ts @@ -5,19 +5,25 @@ * 2.0. */ -import type { CloudStart } from '@kbn/cloud-plugin/public'; -import type { ConsolePluginStart } from '@kbn/console-plugin/public'; +import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public'; +import type { ConsolePluginSetup, ConsolePluginStart } from '@kbn/console-plugin/public'; import type { AppMountParameters, CoreStart } from '@kbn/core/public'; -import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; -import type { SharePluginStart } from '@kbn/share-plugin/public'; -import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; +import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; +import type { + UsageCollectionSetup, + UsageCollectionStart, +} from '@kbn/usage-collection-plugin/public'; import type { MappingProperty, MappingPropertyBase, } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import type { IndexManagementPluginStart } from '@kbn/index-management-shared-types'; +import type { + IndexManagementPluginSetup, + IndexManagementPluginStart, +} from '@kbn/index-management-shared-types'; import type { AppDeepLinkId } from '@kbn/core-chrome-browser'; -import { ServerlessPluginStart } from '@kbn/serverless/public'; +import type { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; +import type { AvailableLanguages } from './code_examples'; export interface SearchIndicesPluginSetup { enabled: boolean; @@ -31,14 +37,20 @@ export interface SearchIndicesPluginStart { startRoute: string; } -export interface AppPluginStartDependencies { - navigation: NavigationPublicPluginStart; +export interface AppPluginSetupDependencies { + console?: ConsolePluginSetup; + cloud?: CloudSetup; + indexManagement: IndexManagementPluginSetup; + share: SharePluginSetup; + serverless?: ServerlessPluginSetup; + usageCollection?: UsageCollectionSetup; } export interface SearchIndicesAppPluginStartDependencies { console?: ConsolePluginStart; cloud?: CloudStart; share: SharePluginStart; + serverless?: ServerlessPluginStart; usageCollection?: UsageCollectionStart; indexManagement: IndexManagementPluginStart; } @@ -50,8 +62,6 @@ export interface SearchIndicesServicesContextDeps { export type SearchIndicesServicesContext = CoreStart & SearchIndicesAppPluginStartDependencies & { history: AppMountParameters['history']; - indexManagement: IndexManagementPluginStart; - serverless: ServerlessPluginStart; }; export interface AppUsageTracker { @@ -123,3 +133,14 @@ export interface IngestDataCodeExamples { python: IngestDataCodeDefinition; javascript: IngestDataCodeDefinition; } + +export interface CreateIndexFormState { + indexName: string; + defaultIndexName: string; + codingLanguage: AvailableLanguages; +} + +export enum CreateIndexViewMode { + UI = 'ui', + Code = 'code', +} diff --git a/x-pack/plugins/search_indices/public/utils/indices.test.ts b/x-pack/plugins/search_indices/public/utils/indices.test.ts index 8ddd7cbb56fc..a3b6654a1209 100644 --- a/x-pack/plugins/search_indices/public/utils/indices.test.ts +++ b/x-pack/plugins/search_indices/public/utils/indices.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { generateRandomIndexName, isValidIndexName } from './indices'; +import { generateRandomIndexName, isValidIndexName, getFirstNewIndexName } from './indices'; describe('indices utils', function () { describe('generateRandomIndexName', function () { @@ -46,4 +46,31 @@ describe('indices utils', function () { expect(isValidIndexName(indexName)).toBe(true); }); }); + + describe('getFirstNewIndexName', function () { + it('returns undefined when lists are the same', () => { + expect(getFirstNewIndexName([], [])).toEqual(undefined); + expect(getFirstNewIndexName(['index'], ['index'])).toEqual(undefined); + expect(getFirstNewIndexName(['index', 'test'], ['index', 'test'])).toEqual(undefined); + }); + + it('returns new item when it exists', () => { + expect(getFirstNewIndexName([], ['index'])).toEqual('index'); + expect(getFirstNewIndexName(['index'], ['index', 'test'])).toEqual('test'); + expect(getFirstNewIndexName(['index', 'test'], ['index', 'test', 'unit-test'])).toEqual( + 'unit-test' + ); + expect(getFirstNewIndexName(['index', 'test'], ['unit-test', 'index', 'test'])).toEqual( + 'unit-test' + ); + }); + it('returns first new item when it multiple new indices exists', () => { + expect(getFirstNewIndexName([], ['index', 'test'])).toEqual('index'); + expect(getFirstNewIndexName(['index'], ['test', 'index', 'unit-test'])).toEqual('test'); + }); + it('can handle old indices being removed', () => { + expect(getFirstNewIndexName(['index'], ['test'])).toEqual('test'); + expect(getFirstNewIndexName(['test', 'index', 'unit-test'], ['index', 'new'])).toEqual('new'); + }); + }); }); diff --git a/x-pack/plugins/search_indices/public/utils/indices.ts b/x-pack/plugins/search_indices/public/utils/indices.ts index 21c6e672af08..3812eea8757b 100644 --- a/x-pack/plugins/search_indices/public/utils/indices.ts +++ b/x-pack/plugins/search_indices/public/utils/indices.ts @@ -35,3 +35,12 @@ export function generateRandomIndexName( return result; } + +export function getFirstNewIndexName(startingIndexNames: string[], currentIndexNames: string[]) { + for (const index of currentIndexNames) { + if (startingIndexNames.indexOf(index) === -1) { + return index; + } + } + return undefined; +} diff --git a/x-pack/plugins/search_indices/tsconfig.json b/x-pack/plugins/search_indices/tsconfig.json index 61b82f448549..341dd230cee5 100644 --- a/x-pack/plugins/search_indices/tsconfig.json +++ b/x-pack/plugins/search_indices/tsconfig.json @@ -12,7 +12,6 @@ ], "kbn_references": [ "@kbn/core", - "@kbn/navigation-plugin", "@kbn/config-schema", "@kbn/core-elasticsearch-server", "@kbn/logging", @@ -39,7 +38,8 @@ "@kbn/search-shared-ui", "@kbn/deeplinks-search", "@kbn/core-chrome-browser", - "@kbn/serverless" + "@kbn/serverless", + "@kbn/utility-types" ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/search_inference_endpoints/kibana.jsonc b/x-pack/plugins/search_inference_endpoints/kibana.jsonc index ce4939790174..7531316cd12e 100644 --- a/x-pack/plugins/search_inference_endpoints/kibana.jsonc +++ b/x-pack/plugins/search_inference_endpoints/kibana.jsonc @@ -2,6 +2,8 @@ "type": "plugin", "id": "@kbn/search-inference-endpoints", "owner": "@elastic/search-kibana", + "group": "platform", + "visibility": "shared", "plugin": { "id": "searchInferenceEndpoints", "server": true, diff --git a/x-pack/plugins/search_notebooks/kibana.jsonc b/x-pack/plugins/search_notebooks/kibana.jsonc index e9432a5559ce..2944f22f8338 100644 --- a/x-pack/plugins/search_notebooks/kibana.jsonc +++ b/x-pack/plugins/search_notebooks/kibana.jsonc @@ -2,6 +2,8 @@ "type": "plugin", "id": "@kbn/search-notebooks", "owner": "@elastic/search-kibana", + "group": "search", + "visibility": "private", "description": "Plugin to provide access to and rendering of python notebooks for use in the persistent developer console.", "plugin": { "id": "searchNotebooks", diff --git a/x-pack/plugins/search_playground/kibana.jsonc b/x-pack/plugins/search_playground/kibana.jsonc index e9dedf0fe716..8b99add8587f 100644 --- a/x-pack/plugins/search_playground/kibana.jsonc +++ b/x-pack/plugins/search_playground/kibana.jsonc @@ -2,6 +2,9 @@ "type": "plugin", "id": "@kbn/search-playground", "owner": "@elastic/search-kibana", + // @kbn/enterprise-search-plugin (platform) and @kbn/serverless-search (search) depend on it + "group": "platform", + "visibility": "shared", "plugin": { "id": "searchPlayground", "server": true, diff --git a/x-pack/plugins/search_playground/public/components/app.tsx b/x-pack/plugins/search_playground/public/components/app.tsx index 4f371ea5d15b..914a429845e9 100644 --- a/x-pack/plugins/search_playground/public/components/app.tsx +++ b/x-pack/plugins/search_playground/public/components/app.tsx @@ -18,10 +18,11 @@ import { Chat } from './chat'; import { SearchMode } from './search_mode/search_mode'; import { SearchPlaygroundSetupPage } from './setup_page/search_playground_setup_page'; import { usePageMode } from '../hooks/use_page_mode'; +import { useKibana } from '../hooks/use_kibana'; export interface AppProps { showDocs?: boolean; - pageMode?: PlaygroundPageMode; + pageMode?: 'chat' | 'search'; } export enum ViewMode { @@ -33,6 +34,7 @@ export const App: React.FC = ({ showDocs = false, pageMode = PlaygroundPageMode.chat, }) => { + const { services } = useKibana(); const [selectedMode, setSelectedMode] = useState(ViewMode.chat); const { data: connectors } = useLoadConnectors(); const hasSelectedIndices = Boolean( @@ -41,7 +43,10 @@ export const App: React.FC = ({ }).length ); const handleModeChange = (id: ViewMode) => setSelectedMode(id); - const handlePageModeChange = (mode: PlaygroundPageMode) => setSelectedPageMode(mode); + const handlePageModeChange = (mode: PlaygroundPageMode) => { + services.application?.navigateToUrl(`./${mode}`); + setSelectedPageMode(mode); + }; const { showSetupPage, pageMode: selectedPageMode, @@ -49,7 +54,7 @@ export const App: React.FC = ({ } = usePageMode({ hasSelectedIndices, hasConnectors: Boolean(connectors?.length), - initialPageMode: pageMode, + initialPageMode: pageMode === 'chat' ? PlaygroundPageMode.chat : PlaygroundPageMode.search, }); const restrictedWidth = selectedPageMode === PlaygroundPageMode.search && selectedMode === 'chat'; diff --git a/x-pack/plugins/search_playground/public/components/search_mode/search_mode.tsx b/x-pack/plugins/search_playground/public/components/search_mode/search_mode.tsx index 94e6337f1a03..8a27f3ac3d83 100644 --- a/x-pack/plugins/search_playground/public/components/search_mode/search_mode.tsx +++ b/x-pack/plugins/search_playground/public/components/search_mode/search_mode.tsx @@ -69,6 +69,7 @@ export const SearchMode: React.FC = () => { name={ChatFormFields.searchQuery} render={({ field }) => ( { services: { application, share }, } = useKibana(); const createIndexLocator = useMemo( - () => share.url.locators.get('CREATE_INDEX_LOCATOR_ID'), + () => + share.url.locators.get('CREATE_INDEX_LOCATOR_ID') ?? + share.url.locators.get('SEARCH_CREATE_INDEX'), [share.url.locators] ); const handleNavigateToIndex = useCallback(async () => { diff --git a/x-pack/plugins/search_playground/public/index.ts b/x-pack/plugins/search_playground/public/index.ts index c6d31b75b07f..6a0bdff7784b 100644 --- a/x-pack/plugins/search_playground/public/index.ts +++ b/x-pack/plugins/search_playground/public/index.ts @@ -13,4 +13,8 @@ export function plugin(initializerContext: PluginInitializerContext) { return new SearchPlaygroundPlugin(initializerContext); } -export type { SearchPlaygroundPluginSetup, SearchPlaygroundPluginStart } from './types'; +export type { + SearchPlaygroundPluginSetup, + SearchPlaygroundPluginStart, + PlaygroundPageMode, +} from './types'; diff --git a/x-pack/plugins/search_playground/tsconfig.json b/x-pack/plugins/search_playground/tsconfig.json index 29c144ff4bac..73204bade51c 100644 --- a/x-pack/plugins/search_playground/tsconfig.json +++ b/x-pack/plugins/search_playground/tsconfig.json @@ -45,7 +45,7 @@ "@kbn/data-views-plugin", "@kbn/discover-utils", "@kbn/data-plugin", - "@kbn/search-index-documents" + "@kbn/search-index-documents", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/searchprofiler/public/application/components/highlight_details_flyout/highlight_details_table.tsx b/x-pack/plugins/searchprofiler/public/application/components/highlight_details_flyout/highlight_details_table.tsx index 7fe8c167ed5d..14ba16fbacbd 100644 --- a/x-pack/plugins/searchprofiler/public/application/components/highlight_details_flyout/highlight_details_table.tsx +++ b/x-pack/plugins/searchprofiler/public/application/components/highlight_details_flyout/highlight_details_table.tsx @@ -30,7 +30,7 @@ export const HighlightDetailsTable = ({ breakdown }: Props) => { name: 'Time', render: (item: BreakdownItem) => ( - {nsToPretty(item.time, 1)} + {item.key.endsWith('_count') ? item.time : nsToPretty(item.time, 1)} ), }, diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx index 406e102b4529..fb472191b561 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiButtonGroup } from '@elastic/eui'; +import { EuiButtonGroup, EuiThemeProvider } from '@elastic/eui'; import React from 'react'; import { @@ -48,21 +48,28 @@ const displaySpaces: Space[] = [ }, ]; +const renderComponent = (props: React.ComponentProps) => { + return mountWithIntl( + + + + ); +}; + describe('PrivilegeSpaceForm', () => { it('renders an empty form when the role contains no Kibana privileges', () => { const role = createRole(); const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures); - const wrapper = mountWithIntl( - - ); + const wrapper = renderComponent({ + role, + spaces: displaySpaces, + kibanaPrivileges, + privilegeIndex: -1, + canCustomizeSubFeaturePrivileges: true, + onChange: jest.fn(), + onCancel: jest.fn(), + }); expect( wrapper.find(EuiButtonGroup).filter('[name="basePrivilegeButtonGroup"]').props().idSelected @@ -110,17 +117,15 @@ describe('PrivilegeSpaceForm', () => { ]); const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures); - const wrapper = mountWithIntl( - - ); + const wrapper = renderComponent({ + role, + spaces: displaySpaces, + kibanaPrivileges, + canCustomizeSubFeaturePrivileges: true, + privilegeIndex: 0, + onChange: jest.fn(), + onCancel: jest.fn(), + }); expect( wrapper.find(EuiButtonGroup).filter('[name="basePrivilegeButtonGroup"]').props().idSelected @@ -178,17 +183,15 @@ describe('PrivilegeSpaceForm', () => { ]); const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures); - const wrapper = mountWithIntl( - - ); + const wrapper = renderComponent({ + role, + spaces: displaySpaces, + kibanaPrivileges, + canCustomizeSubFeaturePrivileges: true, + privilegeIndex: 0, + onChange: jest.fn(), + onCancel: jest.fn(), + }); expect( wrapper.find(EuiButtonGroup).filter('[name="basePrivilegeButtonGroup"]').props().idSelected @@ -249,16 +252,15 @@ describe('PrivilegeSpaceForm', () => { const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures); - const wrapper = mountWithIntl( - - ); + const wrapper = renderComponent({ + role, + spaces: displaySpaces, + kibanaPrivileges, + privilegeIndex: -1, + canCustomizeSubFeaturePrivileges: true, + onChange: jest.fn(), + onCancel: jest.fn(), + }); wrapper.find(SpaceSelector).props().onChange(['*']); @@ -286,17 +288,15 @@ describe('PrivilegeSpaceForm', () => { ]); const kibanaPrivileges = createKibanaPrivileges(kibanaFeatures); - const wrapper = mountWithIntl( - - ); + const wrapper = renderComponent({ + role, + spaces: displaySpaces, + kibanaPrivileges, + canCustomizeSubFeaturePrivileges: true, + privilegeIndex: 0, + onChange: jest.fn(), + onCancel: jest.fn(), + }); expect( wrapper.find(EuiButtonGroup).filter('[name="basePrivilegeButtonGroup"]').props().idSelected @@ -360,17 +360,15 @@ describe('PrivilegeSpaceForm', () => { const onChange = jest.fn(); - const wrapper = mountWithIntl( - - ); + const wrapper = renderComponent({ + role, + spaces: displaySpaces, + kibanaPrivileges, + canCustomizeSubFeaturePrivileges: true, + privilegeIndex: 0, + onChange, + onCancel: jest.fn(), + }); findTestSubject(wrapper, 'changeAllPrivilegesButton').simulate('click'); findTestSubject(wrapper, 'changeAllPrivileges-read').simulate('click'); @@ -418,17 +416,15 @@ describe('PrivilegeSpaceForm', () => { const canCustomize = Symbol('can customize') as unknown as boolean; - const wrapper = mountWithIntl( - - ); + const wrapper = renderComponent({ + role, + spaces: displaySpaces, + kibanaPrivileges, + canCustomizeSubFeaturePrivileges: canCustomize, + privilegeIndex: 0, + onChange, + onCancel: jest.fn(), + }); expect(wrapper.find(FeatureTable).props().canCustomizeSubFeaturePrivileges).toBe(canCustomize); }); @@ -464,17 +460,15 @@ describe('PrivilegeSpaceForm', () => { onChange.mockReset(); }); it('still allow other features privileges to be changed via "change read"', () => { - const wrapper = mountWithIntl( - - ); + const wrapper = renderComponent({ + role, + spaces: displaySpaces, + kibanaPrivileges, + canCustomizeSubFeaturePrivileges: true, + privilegeIndex: 0, + onChange, + onCancel: jest.fn(), + }); findTestSubject(wrapper, 'changeAllPrivilegesButton').simulate('click'); findTestSubject(wrapper, 'changeAllPrivileges-read').simulate('click'); @@ -510,17 +504,15 @@ describe('PrivilegeSpaceForm', () => { }); it('still allow all privileges to be changed via "change all"', () => { - const wrapper = mountWithIntl( - - ); + const wrapper = renderComponent({ + role, + spaces: displaySpaces, + kibanaPrivileges, + canCustomizeSubFeaturePrivileges: true, + privilegeIndex: 0, + onChange, + onCancel: jest.fn(), + }); findTestSubject(wrapper, 'changeAllPrivilegesButton').simulate('click'); findTestSubject(wrapper, 'changeAllPrivileges-all').simulate('click'); @@ -587,17 +579,15 @@ describe('PrivilegeSpaceForm', () => { }); it('still allow all features privileges to be changed via "change read" in foo space', () => { - const wrapper = mountWithIntl( - - ); + const wrapper = renderComponent({ + role, + spaces: displaySpaces, + kibanaPrivileges, + canCustomizeSubFeaturePrivileges: true, + privilegeIndex: 0, + onChange, + onCancel: jest.fn(), + }); findTestSubject(wrapper, 'changeAllPrivilegesButton').simulate('click'); findTestSubject(wrapper, 'changeAllPrivileges-read').simulate('click'); @@ -631,17 +621,15 @@ describe('PrivilegeSpaceForm', () => { }); it('still allow other features privileges to be changed via "change all" in foo space', () => { - const wrapper = mountWithIntl( - - ); + const wrapper = renderComponent({ + role, + spaces: displaySpaces, + kibanaPrivileges, + canCustomizeSubFeaturePrivileges: true, + privilegeIndex: 0, + onChange, + onCancel: jest.fn(), + }); findTestSubject(wrapper, 'changeAllPrivilegesButton').simulate('click'); findTestSubject(wrapper, 'changeAllPrivileges-all').simulate('click'); @@ -692,17 +680,15 @@ describe('PrivilegeSpaceForm', () => { spaces: ['bar'], }, ]); - const wrapper = mountWithIntl( - - ); + const wrapper = renderComponent({ + role: roleAllSpace, + spaces: displaySpaces, + kibanaPrivileges, + canCustomizeSubFeaturePrivileges: true, + privilegeIndex: 0, + onChange, + onCancel: jest.fn(), + }); findTestSubject(wrapper, 'changeAllPrivilegesButton').simulate('click'); findTestSubject(wrapper, 'changeAllPrivileges-all').simulate('click'); diff --git a/x-pack/plugins/security/server/authorization/api_authorization.ts b/x-pack/plugins/security/server/authorization/api_authorization.ts index 2b99c2a176ac..888d74e7d7bb 100644 --- a/x-pack/plugins/security/server/authorization/api_authorization.ts +++ b/x-pack/plugins/security/server/authorization/api_authorization.ts @@ -48,10 +48,6 @@ export function initAPIAuthorization( if (security) { if (isAuthzDisabled(security.authz)) { - logger.warn( - `Route authz is disabled for ${request.url.pathname}${request.url.search}": ${security.authz.reason}` - ); - return toolkit.next(); } diff --git a/x-pack/plugins/security/server/routes/analytics/authentication_type.ts b/x-pack/plugins/security/server/routes/analytics/authentication_type.ts index f2bf76c71b1a..92094a65da7b 100644 --- a/x-pack/plugins/security/server/routes/analytics/authentication_type.ts +++ b/x-pack/plugins/security/server/routes/analytics/authentication_type.ts @@ -31,6 +31,13 @@ export function defineRecordAnalyticsOnAuthTypeRoutes({ router.post( { path: '/internal/security/analytics/_record_auth_type', + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the scoped ES cluster client of the internal authentication service', + }, + }, validate: { body: schema.nullable( schema.object({ signature: schema.string(), timestamp: schema.number() }) diff --git a/x-pack/plugins/security/server/routes/analytics/record_violations.ts b/x-pack/plugins/security/server/routes/analytics/record_violations.ts index 826a304f1656..bec224a6d3ee 100644 --- a/x-pack/plugins/security/server/routes/analytics/record_violations.ts +++ b/x-pack/plugins/security/server/routes/analytics/record_violations.ts @@ -135,6 +135,13 @@ export function defineRecordViolations({ router, analyticsService }: RouteDefini router.post( { path: '/internal/security/analytics/_record_violations', + security: { + authz: { + enabled: false, + reason: + 'This route is used by browsers to report CSP and Permission Policy violations. These requests are sent without authentication per the browser spec.', + }, + }, validate: { /** * Chrome supports CSP3 spec and sends an array of reports. Safari only sends a single diff --git a/x-pack/plugins/security/server/routes/anonymous_access/get_capabilities.ts b/x-pack/plugins/security/server/routes/anonymous_access/get_capabilities.ts index 220fb1515df4..84c8ed17e596 100644 --- a/x-pack/plugins/security/server/routes/anonymous_access/get_capabilities.ts +++ b/x-pack/plugins/security/server/routes/anonymous_access/get_capabilities.ts @@ -15,7 +15,17 @@ export function defineAnonymousAccessGetCapabilitiesRoutes({ getAnonymousAccessService, }: RouteDefinitionParams) { router.get( - { path: '/internal/security/anonymous_access/capabilities', validate: false }, + { + path: '/internal/security/anonymous_access/capabilities', + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the scoped ES cluster client of the anonymous access service', + }, + }, + validate: false, + }, async (_context, request, response) => { const anonymousAccessService = getAnonymousAccessService(); return response.ok({ body: await anonymousAccessService.getCapabilities(request) }); diff --git a/x-pack/plugins/security/server/routes/anonymous_access/get_state.ts b/x-pack/plugins/security/server/routes/anonymous_access/get_state.ts index 28745c80a5f4..8911588b7210 100644 --- a/x-pack/plugins/security/server/routes/anonymous_access/get_state.ts +++ b/x-pack/plugins/security/server/routes/anonymous_access/get_state.ts @@ -18,7 +18,16 @@ export function defineAnonymousAccessGetStateRoutes({ getAnonymousAccessService, }: RouteDefinitionParams) { router.get( - { path: '/internal/security/anonymous_access/state', validate: false }, + { + path: '/internal/security/anonymous_access/state', + security: { + authz: { + enabled: false, + reason: 'This route is used for anonymous access', + }, + }, + validate: false, + }, async (_context, _request, response) => { const anonymousAccessService = getAnonymousAccessService(); const accessURLParameters = anonymousAccessService.accessURLParameters diff --git a/x-pack/plugins/security/server/routes/api_keys/create.ts b/x-pack/plugins/security/server/routes/api_keys/create.ts index 59d743e3726a..963e6c7ced35 100644 --- a/x-pack/plugins/security/server/routes/api_keys/create.ts +++ b/x-pack/plugins/security/server/routes/api_keys/create.ts @@ -32,6 +32,13 @@ export function defineCreateApiKeyRoutes({ router.post( { path: '/internal/security/api_key', + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the scoped ES cluster client of the internal authentication service', + }, + }, validate: { body: schema.oneOf([ restApiKeySchema, diff --git a/x-pack/plugins/security/server/routes/api_keys/enabled.ts b/x-pack/plugins/security/server/routes/api_keys/enabled.ts index c94c8af61e24..dd06c93a71e8 100644 --- a/x-pack/plugins/security/server/routes/api_keys/enabled.ts +++ b/x-pack/plugins/security/server/routes/api_keys/enabled.ts @@ -16,6 +16,13 @@ export function defineEnabledApiKeysRoutes({ router.get( { path: '/internal/security/api_key/_enabled', + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the scoped ES cluster client of the internal authentication service', + }, + }, validate: false, }, createLicensedRouteHandler(async (context, request, response) => { diff --git a/x-pack/plugins/security/server/routes/api_keys/has_active.ts b/x-pack/plugins/security/server/routes/api_keys/has_active.ts index bf432b186104..b1cc220f802b 100644 --- a/x-pack/plugins/security/server/routes/api_keys/has_active.ts +++ b/x-pack/plugins/security/server/routes/api_keys/has_active.ts @@ -22,6 +22,12 @@ export function defineHasApiKeysRoutes({ router.get( { path: '/internal/security/api_key/_has_active', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to the scoped ES cluster client of the internal authentication service, and to Core's ES client`, + }, + }, validate: false, options: { access: 'internal', diff --git a/x-pack/plugins/security/server/routes/api_keys/invalidate.ts b/x-pack/plugins/security/server/routes/api_keys/invalidate.ts index 1983dbf2344e..f2d72185d0b1 100644 --- a/x-pack/plugins/security/server/routes/api_keys/invalidate.ts +++ b/x-pack/plugins/security/server/routes/api_keys/invalidate.ts @@ -21,6 +21,12 @@ export function defineInvalidateApiKeysRoutes({ router }: RouteDefinitionParams) router.post( { path: '/internal/security/api_key/invalidate', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's ES client`, + }, + }, validate: { body: schema.object({ apiKeys: schema.arrayOf(schema.object({ id: schema.string(), name: schema.string() })), diff --git a/x-pack/plugins/security/server/routes/api_keys/query.ts b/x-pack/plugins/security/server/routes/api_keys/query.ts index 9fe8fdbdc734..382d3a290aa7 100644 --- a/x-pack/plugins/security/server/routes/api_keys/query.ts +++ b/x-pack/plugins/security/server/routes/api_keys/query.ts @@ -25,6 +25,12 @@ export function defineQueryApiKeysAndAggregationsRoute({ // on behalf of the user making the request and governed by the user's own cluster privileges. { path: '/internal/security/api_key/_query', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to the scoped ES cluster client of the internal authentication service, and to Core's ES client`, + }, + }, validate: { body: schema.object({ query: schema.maybe(schema.object({}, { unknowns: 'allow' })), diff --git a/x-pack/plugins/security/server/routes/api_keys/update.ts b/x-pack/plugins/security/server/routes/api_keys/update.ts index a7fe43c46e20..364a0af0b95a 100644 --- a/x-pack/plugins/security/server/routes/api_keys/update.ts +++ b/x-pack/plugins/security/server/routes/api_keys/update.ts @@ -34,6 +34,12 @@ export function defineUpdateApiKeyRoutes({ router.put( { path: '/internal/security/api_key', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to the scoped ES cluster client of the internal authentication service`, + }, + }, validate: { body: schema.oneOf([ updateRestApiKeySchema, diff --git a/x-pack/plugins/security/server/routes/authentication/common.ts b/x-pack/plugins/security/server/routes/authentication/common.ts index b519171fd4fe..0c91a6c7f385 100644 --- a/x-pack/plugins/security/server/routes/authentication/common.ts +++ b/x-pack/plugins/security/server/routes/authentication/common.ts @@ -43,6 +43,12 @@ export function defineCommonRoutes({ router.get( { path, + security: { + authz: { + enabled: false, + reason: 'This route must remain accessible to 3rd-party IdPs', + }, + }, // Allow unknown query parameters as this endpoint can be hit by the 3rd-party with any // set of query string parameters (e.g. SAML/OIDC logout request/response parameters). validate: { query: schema.object({}, { unknowns: 'allow' }) }, @@ -92,7 +98,17 @@ export function defineCommonRoutes({ ]) { const deprecated = path === '/api/security/v1/me'; router.get( - { path, validate: false, options: { access: deprecated ? 'public' : 'internal' } }, + { + path, + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's security service; there must be an authenticated user for this route to return information`, + }, + }, + validate: false, + options: { access: deprecated ? 'public' : 'internal' }, + }, createLicensedRouteHandler(async (context, request, response) => { if (deprecated) { logger.warn( @@ -135,10 +151,16 @@ export function defineCommonRoutes({ } // Register the login route for serverless for the time being. Note: This route will move into the buildFlavor !== 'serverless' block below. See next line. - // ToDo: In the serverless environment, we do not support API login - the only valid authentication methodology (or maybe just method or mechanism?) is SAML + // ToDo: In the serverless environment, we do not support API login - the only valid authentication type is SAML router.post( { path: '/internal/security/login', + security: { + authz: { + enabled: false, + reason: `This route provides basic and token login capbility, which is delegated to the internal authentication service`, + }, + }, validate: { body: schema.object({ providerType: schema.string(), @@ -183,7 +205,16 @@ export function defineCommonRoutes({ if (buildFlavor !== 'serverless') { // In the serverless offering, the access agreement functionality isn't available. router.post( - { path: '/internal/security/access_agreement/acknowledge', validate: false }, + { + path: '/internal/security/access_agreement/acknowledge', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to the internal authentication service; there must be an authenticated user for this route to function`, + }, + }, + validate: false, + }, createLicensedRouteHandler(async (context, request, response) => { // If license doesn't allow access agreement we shouldn't handle request. if (!license.getFeatures().allowAccessAgreement) { diff --git a/x-pack/plugins/security/server/routes/authentication/oidc.ts b/x-pack/plugins/security/server/routes/authentication/oidc.ts index 69c3ce170067..bb1ed6959e69 100644 --- a/x-pack/plugins/security/server/routes/authentication/oidc.ts +++ b/x-pack/plugins/security/server/routes/authentication/oidc.ts @@ -87,6 +87,12 @@ export function defineOIDCRoutes({ router.get( { path, + security: { + authz: { + enabled: false, + reason: 'This route must remain accessible to 3rd-party OIDC providers', + }, + }, validate: { query: schema.object( { @@ -176,6 +182,12 @@ export function defineOIDCRoutes({ router.post( { path, + security: { + authz: { + enabled: false, + reason: 'This route must remain accessible to 3rd-party OIDC providers', + }, + }, validate: { body: schema.object( { @@ -221,6 +233,12 @@ export function defineOIDCRoutes({ router.get( { path: '/api/security/oidc/initiate_login', + security: { + authz: { + enabled: false, + reason: 'This route must remain accessible to 3rd-party OIDC providers', + }, + }, validate: { query: schema.object( { diff --git a/x-pack/plugins/security/server/routes/authentication/saml.ts b/x-pack/plugins/security/server/routes/authentication/saml.ts index 3c72fd908e6c..8cee1df2da88 100644 --- a/x-pack/plugins/security/server/routes/authentication/saml.ts +++ b/x-pack/plugins/security/server/routes/authentication/saml.ts @@ -30,6 +30,12 @@ export function defineSAMLRoutes({ router.post( { path, + security: { + authz: { + enabled: false, + reason: 'This route must remain accessible to 3rd-party SAML providers', + }, + }, validate: { body: schema.object( { SAMLResponse: schema.string(), RelayState: schema.maybe(schema.string()) }, diff --git a/x-pack/plugins/security/server/routes/authorization/privileges/get.ts b/x-pack/plugins/security/server/routes/authorization/privileges/get.ts index b7204faaa7ca..23fb7ccd9bf3 100644 --- a/x-pack/plugins/security/server/routes/authorization/privileges/get.ts +++ b/x-pack/plugins/security/server/routes/authorization/privileges/get.ts @@ -14,6 +14,13 @@ export function defineGetPrivilegesRoutes({ router, authz }: RouteDefinitionPara router.get( { path: '/api/security/privileges', + security: { + authz: { + enabled: false, + reason: + 'This route is opted out from authorization because it returns only the global list of Kibana privileges', + }, + }, validate: { query: schema.object({ // We don't use `schema.boolean` here, because all query string parameters are treated as diff --git a/x-pack/plugins/security/server/routes/authorization/privileges/get_builtin.ts b/x-pack/plugins/security/server/routes/authorization/privileges/get_builtin.ts index 9a9c2dd6fcc7..1a35875de72e 100644 --- a/x-pack/plugins/security/server/routes/authorization/privileges/get_builtin.ts +++ b/x-pack/plugins/security/server/routes/authorization/privileges/get_builtin.ts @@ -9,7 +9,16 @@ import type { RouteDefinitionParams } from '../..'; export function defineGetBuiltinPrivilegesRoutes({ router }: RouteDefinitionParams) { router.get( - { path: '/internal/security/esPrivileges/builtin', validate: false }, + { + path: '/internal/security/esPrivileges/builtin', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, + validate: false, + }, async (context, request, response) => { const esClient = (await context.core).elasticsearch.client; const privileges = await esClient.asCurrentUser.security.getBuiltinPrivileges(); diff --git a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts index 07f314da4232..b4ff278db219 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/delete.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/delete.ts @@ -25,6 +25,12 @@ export function defineDeleteRolesRoutes({ router }: RouteDefinitionParams) { .addVersion( { version: API_VERSIONS.roles.public.v1, + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { request: { params: schema.object({ name: schema.string({ minLength: 1 }) }), diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get.ts b/x-pack/plugins/security/server/routes/authorization/roles/get.ts index 031da53092b0..d088ada56854 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get.ts @@ -32,6 +32,12 @@ export function defineGetRolesRoutes({ .addVersion( { version: API_VERSIONS.roles.public.v1, + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { request: { params: schema.object({ diff --git a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts index 5979922cd64e..9a6d1d56569c 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/get_all.ts @@ -33,6 +33,12 @@ export function defineGetAllRolesRoutes({ .addVersion( { version: API_VERSIONS.roles.public.v1, + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { request: { query: schema.maybe( diff --git a/x-pack/plugins/security/server/routes/authorization/roles/post.ts b/x-pack/plugins/security/server/routes/authorization/roles/post.ts index 949553e960c9..4a41533e93a8 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/post.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/post.ts @@ -52,6 +52,12 @@ export function defineBulkCreateOrUpdateRolesRoutes({ .addVersion( { version: API_VERSIONS.roles.public.v1, + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { request: { body: getBulkCreateOrUpdatePayloadSchema(() => { diff --git a/x-pack/plugins/security/server/routes/authorization/roles/put.ts b/x-pack/plugins/security/server/routes/authorization/roles/put.ts index 268c84ff7420..ce0b8222d412 100644 --- a/x-pack/plugins/security/server/routes/authorization/roles/put.ts +++ b/x-pack/plugins/security/server/routes/authorization/roles/put.ts @@ -35,6 +35,12 @@ export function definePutRolesRoutes({ .addVersion( { version: API_VERSIONS.roles.public.v1, + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { request: { params: schema.object({ diff --git a/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.ts b/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.ts index 536220eff03d..4c83455844a2 100644 --- a/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.ts +++ b/x-pack/plugins/security/server/routes/authorization/spaces/share_saved_object_permissions.ts @@ -19,6 +19,12 @@ export function defineShareSavedObjectPermissionRoutes({ router.get( { path: '/internal/security/_share_saved_object_permissions', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to the internal authorization service's checkPrivilegesWithRequest function`, + }, + }, validate: { query: schema.object({ type: schema.string() }) }, }, createLicensedRouteHandler(async (context, request, response) => { diff --git a/x-pack/plugins/security/server/routes/deprecations/kibana_user_role.ts b/x-pack/plugins/security/server/routes/deprecations/kibana_user_role.ts index 638a8f8a1bc7..e465369ff091 100644 --- a/x-pack/plugins/security/server/routes/deprecations/kibana_user_role.ts +++ b/x-pack/plugins/security/server/routes/deprecations/kibana_user_role.ts @@ -23,6 +23,12 @@ export function defineKibanaUserRoleDeprecationRoutes({ router, logger }: RouteD router.post( { path: '/internal/security/deprecations/kibana_user_role/_fix_users', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: false, }, createLicensedRouteHandler(async (context, request, response) => { @@ -88,6 +94,12 @@ export function defineKibanaUserRoleDeprecationRoutes({ router, logger }: RouteD router.post( { path: '/internal/security/deprecations/kibana_user_role/_fix_role_mappings', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: false, }, createLicensedRouteHandler(async (context, request, response) => { diff --git a/x-pack/plugins/security/server/routes/feature_check/feature_check.ts b/x-pack/plugins/security/server/routes/feature_check/feature_check.ts index b256ee77e55f..6f4cd5b4b265 100644 --- a/x-pack/plugins/security/server/routes/feature_check/feature_check.ts +++ b/x-pack/plugins/security/server/routes/feature_check/feature_check.ts @@ -43,6 +43,12 @@ export function defineSecurityFeatureCheckRoute({ router, logger }: RouteDefinit router.get( { path: '/internal/security/_check_security_features', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: false, }, createLicensedRouteHandler(async (context, request, response) => { diff --git a/x-pack/plugins/security/server/routes/indices/get_fields.ts b/x-pack/plugins/security/server/routes/indices/get_fields.ts index b0ec51339e08..4cfd6845e61b 100644 --- a/x-pack/plugins/security/server/routes/indices/get_fields.ts +++ b/x-pack/plugins/security/server/routes/indices/get_fields.ts @@ -14,6 +14,12 @@ export function defineGetFieldsRoutes({ router }: RouteDefinitionParams) { router.get( { path: '/internal/security/fields/{query}', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { params: schema.object({ query: schema.string() }) }, }, async (context, request, response) => { diff --git a/x-pack/plugins/security/server/routes/role_mapping/delete.ts b/x-pack/plugins/security/server/routes/role_mapping/delete.ts index e305de6e4fcb..8e331600ba49 100644 --- a/x-pack/plugins/security/server/routes/role_mapping/delete.ts +++ b/x-pack/plugins/security/server/routes/role_mapping/delete.ts @@ -15,6 +15,12 @@ export function defineRoleMappingDeleteRoutes({ router }: RouteDefinitionParams) router.delete( { path: '/internal/security/role_mapping/{name}', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { params: schema.object({ name: schema.string(), diff --git a/x-pack/plugins/security/server/routes/role_mapping/get.ts b/x-pack/plugins/security/server/routes/role_mapping/get.ts index ac6e7efaa8b0..2b5ce017fbfb 100644 --- a/x-pack/plugins/security/server/routes/role_mapping/get.ts +++ b/x-pack/plugins/security/server/routes/role_mapping/get.ts @@ -18,6 +18,12 @@ export function defineRoleMappingGetRoutes(params: RouteDefinitionParams) { router.get( { path: '/internal/security/role_mapping/{name?}', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { params: schema.object({ name: schema.maybe(schema.string()), diff --git a/x-pack/plugins/security/server/routes/role_mapping/post.ts b/x-pack/plugins/security/server/routes/role_mapping/post.ts index a9a87d4b2be5..e01dd446b6e5 100644 --- a/x-pack/plugins/security/server/routes/role_mapping/post.ts +++ b/x-pack/plugins/security/server/routes/role_mapping/post.ts @@ -15,6 +15,12 @@ export function defineRoleMappingPostRoutes({ router }: RouteDefinitionParams) { router.post( { path: '/internal/security/role_mapping/{name}', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { params: schema.object({ name: schema.string(), diff --git a/x-pack/plugins/security/server/routes/security_checkup/get_state.ts b/x-pack/plugins/security/server/routes/security_checkup/get_state.ts index 2946c3fa5dee..40da0959c741 100644 --- a/x-pack/plugins/security/server/routes/security_checkup/get_state.ts +++ b/x-pack/plugins/security/server/routes/security_checkup/get_state.ts @@ -29,7 +29,16 @@ export function defineSecurityCheckupGetStateRoutes({ const doesClusterHaveUserData = createClusterDataCheck(); router.get( - { path: '/internal/security/security_checkup/state', validate: false }, + { + path: '/internal/security/security_checkup/state', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, + validate: false, + }, async (context, _request, response) => { const esClient = (await context.core).elasticsearch.client; let displayAlert = false; diff --git a/x-pack/plugins/security/server/routes/session_management/extend.ts b/x-pack/plugins/security/server/routes/session_management/extend.ts index b1626ba4660b..1180303d48aa 100644 --- a/x-pack/plugins/security/server/routes/session_management/extend.ts +++ b/x-pack/plugins/security/server/routes/session_management/extend.ts @@ -14,6 +14,13 @@ export function defineSessionExtendRoutes({ router, basePath }: RouteDefinitionP router.post( { path: '/internal/security/session', + security: { + authz: { + enabled: false, + reason: + 'This route is opted out from authorization because it only redirects to the /internal/security/session endpoint', + }, + }, validate: false, }, async (_context, _request, response) => { diff --git a/x-pack/plugins/security/server/routes/session_management/info.ts b/x-pack/plugins/security/server/routes/session_management/info.ts index 75fae27e8cb1..c49cb7575399 100644 --- a/x-pack/plugins/security/server/routes/session_management/info.ts +++ b/x-pack/plugins/security/server/routes/session_management/info.ts @@ -14,7 +14,17 @@ import type { SessionInfo } from '../../../common/types'; */ export function defineSessionInfoRoutes({ router, getSession }: RouteDefinitionParams) { router.get( - { path: '/internal/security/session', validate: false }, + { + path: '/internal/security/session', + security: { + authz: { + enabled: false, + reason: + 'This route is opted out from authorization because a valid session is required, and it does not return sensative session information', + }, + }, + validate: false, + }, async (_context, request, response) => { const { value: sessionValue } = await getSession().get(request); if (sessionValue) { diff --git a/x-pack/plugins/security/server/routes/user_profile/get_current.ts b/x-pack/plugins/security/server/routes/user_profile/get_current.ts index 9661570e36b4..4621d543b49c 100644 --- a/x-pack/plugins/security/server/routes/user_profile/get_current.ts +++ b/x-pack/plugins/security/server/routes/user_profile/get_current.ts @@ -20,6 +20,13 @@ export function defineGetCurrentUserProfileRoute({ router.get( { path: '/internal/security/user_profile', + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the internal authorization service; a currently authenticated user is required', + }, + }, validate: { query: schema.object({ dataPath: schema.maybe(schema.string()) }), }, diff --git a/x-pack/plugins/security/server/routes/user_profile/update.ts b/x-pack/plugins/security/server/routes/user_profile/update.ts index 9a550ada52ad..a400d0db88b8 100644 --- a/x-pack/plugins/security/server/routes/user_profile/update.ts +++ b/x-pack/plugins/security/server/routes/user_profile/update.ts @@ -27,6 +27,13 @@ export function defineUpdateUserProfileDataRoute({ router.post( { path: '/internal/security/user_profile/_data', + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the internal authorization service; an authenticated user and valid session are required', + }, + }, validate: { body: schema.recordOf(schema.string(), schema.any()), }, diff --git a/x-pack/plugins/security/server/routes/users/change_password.ts b/x-pack/plugins/security/server/routes/users/change_password.ts index bd71785ab954..964d3d6fe888 100644 --- a/x-pack/plugins/security/server/routes/users/change_password.ts +++ b/x-pack/plugins/security/server/routes/users/change_password.ts @@ -24,6 +24,12 @@ export function defineChangeUserPasswordRoutes({ router.post( { path: '/internal/security/users/{username}/password', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to the internal authorization service and the Security plugin's canUserChangePassword function`, + }, + }, validate: { params: schema.object({ username: schema.string({ minLength: 1, maxLength: 1024 }) }), body: schema.object({ diff --git a/x-pack/plugins/security/server/routes/users/create_or_update.ts b/x-pack/plugins/security/server/routes/users/create_or_update.ts index de6adad78b4e..c6c0bcbc4841 100644 --- a/x-pack/plugins/security/server/routes/users/create_or_update.ts +++ b/x-pack/plugins/security/server/routes/users/create_or_update.ts @@ -15,6 +15,12 @@ export function defineCreateOrUpdateUserRoutes({ router }: RouteDefinitionParams router.post( { path: '/internal/security/users/{username}', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { params: schema.object({ username: schema.string({ minLength: 1, maxLength: 1024 }) }), body: schema.object({ diff --git a/x-pack/plugins/security/server/routes/users/delete.ts b/x-pack/plugins/security/server/routes/users/delete.ts index 429adb368574..39f838dff7d8 100644 --- a/x-pack/plugins/security/server/routes/users/delete.ts +++ b/x-pack/plugins/security/server/routes/users/delete.ts @@ -15,6 +15,12 @@ export function defineDeleteUserRoutes({ router }: RouteDefinitionParams) { router.delete( { path: '/internal/security/users/{username}', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { params: schema.object({ username: schema.string({ minLength: 1, maxLength: 1024 }) }), }, diff --git a/x-pack/plugins/security/server/routes/users/disable.ts b/x-pack/plugins/security/server/routes/users/disable.ts index 87f61daca8c9..f2984504922b 100644 --- a/x-pack/plugins/security/server/routes/users/disable.ts +++ b/x-pack/plugins/security/server/routes/users/disable.ts @@ -15,6 +15,12 @@ export function defineDisableUserRoutes({ router }: RouteDefinitionParams) { router.post( { path: '/internal/security/users/{username}/_disable', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { params: schema.object({ username: schema.string({ minLength: 1, maxLength: 1024 }) }), }, diff --git a/x-pack/plugins/security/server/routes/users/enable.ts b/x-pack/plugins/security/server/routes/users/enable.ts index a8a9d62bee93..18ec66683bd5 100644 --- a/x-pack/plugins/security/server/routes/users/enable.ts +++ b/x-pack/plugins/security/server/routes/users/enable.ts @@ -15,6 +15,12 @@ export function defineEnableUserRoutes({ router }: RouteDefinitionParams) { router.post( { path: '/internal/security/users/{username}/_enable', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { params: schema.object({ username: schema.string({ minLength: 1, maxLength: 1024 }) }), }, diff --git a/x-pack/plugins/security/server/routes/users/get.ts b/x-pack/plugins/security/server/routes/users/get.ts index ed18c8437627..076c8c9beeef 100644 --- a/x-pack/plugins/security/server/routes/users/get.ts +++ b/x-pack/plugins/security/server/routes/users/get.ts @@ -15,6 +15,12 @@ export function defineGetUserRoutes({ router }: RouteDefinitionParams) { router.get( { path: '/internal/security/users/{username}', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, validate: { params: schema.object({ username: schema.string({ minLength: 1, maxLength: 1024 }) }), }, diff --git a/x-pack/plugins/security/server/routes/users/get_all.ts b/x-pack/plugins/security/server/routes/users/get_all.ts index eae066418934..c8c340f2b2ce 100644 --- a/x-pack/plugins/security/server/routes/users/get_all.ts +++ b/x-pack/plugins/security/server/routes/users/get_all.ts @@ -11,7 +11,16 @@ import { createLicensedRouteHandler } from '../licensed_route_handler'; export function defineGetAllUsersRoutes({ router }: RouteDefinitionParams) { router.get( - { path: '/internal/security/users', validate: false }, + { + path: '/internal/security/users', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's scoped ES cluster client`, + }, + }, + validate: false, + }, createLicensedRouteHandler(async (context, request, response) => { try { const esClient = (await context.core).elasticsearch.client; diff --git a/x-pack/plugins/security/server/routes/views/access_agreement.ts b/x-pack/plugins/security/server/routes/views/access_agreement.ts index 823fbb0286f3..ff6399f18661 100644 --- a/x-pack/plugins/security/server/routes/views/access_agreement.ts +++ b/x-pack/plugins/security/server/routes/views/access_agreement.ts @@ -35,7 +35,17 @@ export function defineAccessAgreementRoutes({ ); router.get( - { path: '/internal/security/access_agreement/state', validate: false }, + { + path: '/internal/security/access_agreement/state', + security: { + authz: { + enabled: false, + reason: + 'This route is opted out from authorization because it requires only an active session in order to function', + }, + }, + validate: false, + }, createLicensedRouteHandler(async (context, request, response) => { if (!canHandleRequest()) { return response.forbidden({ diff --git a/x-pack/plugins/security/server/routes/views/login.ts b/x-pack/plugins/security/server/routes/views/login.ts index 8cf8459d523b..ed3228c244b5 100644 --- a/x-pack/plugins/security/server/routes/views/login.ts +++ b/x-pack/plugins/security/server/routes/views/login.ts @@ -57,7 +57,18 @@ export function defineLoginRoutes({ ); router.get( - { path: '/internal/security/login_state', validate: false, options: { authRequired: false } }, + { + path: '/internal/security/login_state', + security: { + authz: { + enabled: false, + reason: + 'This route is opted out from authorization because it only provides non-sensative information about authentication provider configuration', + }, + }, + validate: false, + options: { authRequired: false }, + }, async (context, request, response) => { const { allowLogin, layout = 'form' } = license.getFeatures(); const { sortedProviders, selector } = config.authc; diff --git a/x-pack/plugins/security_solution/common/guided_onboarding/translations.ts b/x-pack/plugins/security_solution/common/guided_onboarding/translations.ts index 46017971df1b..ffd758d1a1ff 100644 --- a/x-pack/plugins/security_solution/common/guided_onboarding/translations.ts +++ b/x-pack/plugins/security_solution/common/guided_onboarding/translations.ts @@ -87,6 +87,6 @@ export const CASES_MANUAL_TITLE = i18n.translate( export const CASES_MANUAL_DESCRIPTION = i18n.translate( 'xpack.securitySolution.guideConfig.alertsStep.manualCompletion.description', { - defaultMessage: `After you've explored the case, continue.`, + defaultMessage: `View the case's details by clicking View case in the confirmation message that appears. Alternatively, go to the Insights section of the alert details flyout, find the case you created, and select it. After you've explored the case, continue.`, } ); diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/affected_job_ids.ts b/x-pack/plugins/security_solution/common/machine_learning/affected_job_ids.ts similarity index 100% rename from x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/affected_job_ids.ts rename to x-pack/plugins/security_solution/common/machine_learning/affected_job_ids.ts diff --git a/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/exporting.md b/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/exporting.md new file mode 100644 index 000000000000..f4cbc66779a8 --- /dev/null +++ b/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/exporting.md @@ -0,0 +1,65 @@ +# Prebuilt Rule Export + +This is a test plan for the exporting of prebuilt rules. This feature is an aspect of `Milestone 2` of the [Rule Immutability/Customization](https://github.com/elastic/security-team/issues/1974) epic. + +Status: `in progress`. + +## Useful information + +### Tickets + +- [Rule Immutability/Customization](https://github.com/elastic/security-team/issues/1974) +- [Rule Exporting Feature](https://github.com/elastic/kibana/issues/180167#issue-2227974379) +- [Rule Export API PR](https://github.com/elastic/kibana/pull/194498) + +### Terminology + +- **prebuilt rule**: A rule contained in our `Prebuilt Security Detection Rules` integration in Fleet. +- **custom rule**: A rule defined by the user, which has no relation to the prebuilt rules +- **rule source, or ruleSource**: A field on the rule that defines the rule's categorization + +## Scenarios + +### Core Functionality + +#### Scenario: Exporting prebuilt rule individually +```Gherkin +Given a space with prebuilt rules installed +When the user selects "Export rule" from the "All actions" dropdown on the rule's page +Then the rule should be exported as an NDJSON file +And it should include an "immutable" field with a value of true +And its "ruleSource" "type" should be "external" +And its "ruleSource" "isCustomized" value should depend on whether the rule was customized +``` + +#### Scenario: Exporting prebuilt rules in bulk +```Gherkin +Given a space with prebuilt rules installed +When the user selects prebuilt rules in the alerts table +And chooses "Export" from bulk actions +Then the selected rules should be exported as an NDJSON file +And they should include an "immutable" field with a value of true +And their "ruleSource" "type" should be "external" +And their "ruleSource" "isCustomized" should depend on whether the rule was customized +``` + +#### Scenario: Exporting both prebuilt and custom rules in bulk +```Gherkin +Given a space with prebuilt and custom rules installed +When the user selects prebuilt rules in the alerts table +And chooses "Export" from bulk actions +Then the selected rules should be exported as an NDJSON file +And the prebuilt rules should include an "immutable" field with a value of true +And the custom rules should include an "immutable" field with a value of false +And the prebuilt rules' "ruleSource" "type" should be "external" +And the custom rules' "ruleSource" "type" should be "internal" +``` + +### Error Handling + +#### Scenario: Exporting beyond the export limit +```Gherkin +Given a space with prebuilt and custom rules installed +And the number of rules is greater than the export limit (defaults to 10_000) +Then the request should be rejected as a bad request +``` diff --git a/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/importing.md b/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/importing.md new file mode 100644 index 000000000000..0c947d0a52b9 --- /dev/null +++ b/x-pack/plugins/security_solution/docs/testing/test_plans/detection_response/prebuilt_rules/importing.md @@ -0,0 +1,127 @@ +# Prebuilt Rule Import + +This is a test plan for the importing of prebuilt rules. This feature is an aspect of `Milestone 2` of the [Rule Immutability/Customization](https://github.com/elastic/security-team/issues/1974) epic. + +Status: `in progress`. + +## Useful information + +### Tickets + +- [Rule Immutability/Customization](https://github.com/elastic/security-team/issues/1974) +- [Rule Importing Feature](https://github.com/elastic/kibana/issues/180168) +- [Rule Import API PR](https://github.com/elastic/kibana/pull/190198) + +### Terminology + +- **prebuilt rule**: A rule contained in our `Prebuilt Security Detection Rules` integration in Fleet. +- **custom rule**: A rule defined by the user, which has no relation to the prebuilt rules +- **rule source, or ruleSource**: A field on the rule that defines the rule's categorization + +## Scenarios + +### Core Functionality + +#### Scenario: Importing an unmodified prebuilt rule with a matching rule_id and version + +```Gherkin +Given the import payload contains a prebuilt rule with a matching rule_id and version, identical to the published rule +When the user imports the rule +Then the rule should be created or updated +And the ruleSource type should be "external" +And isCustomized should be false +``` + +#### Scenario: Importing a customized prebuilt rule with a matching rule_id and version + +```Gherkin +Given the import payload contains a prebuilt rule with a matching rule_id and version, modified from the published version +When the user imports the rule +Then the rule should be created or updated +And the ruleSource type should be "external" +And isCustomized should be true +``` + +#### Scenario: Importing a prebuilt rule with a matching rule_id but no matching version + +```Gherkin +Given the import payload contains a prebuilt rule with a matching rule_id but no matching version +When the user imports the rule +Then the rule should be created or updated +And the ruleSource type should be "external" +And isCustomized should be true +``` + +#### Scenario: Importing a prebuilt rule with a non-existent rule_id + +```Gherkin +Given the import payload contains a prebuilt rule with a non-existent rule_id +When the user imports the rule +Then the rule should be created +And the ruleSource type should be "internal" +``` + +#### Scenario: Importing a prebuilt rule without a rule_id field + +```Gherkin +Given the import payload contains a prebuilt rule without a rule_id field +When the user imports the rule +Then the import should be rejected with a message "rule_id field is required" +``` + +#### Scenario: Importing a prebuilt rule with a matching rule_id but missing a version field + +```Gherkin +Given the import payload contains a prebuilt rule without a version field +When the user imports the rule +Then the import should be rejected with a message "version field is required" +``` + +#### Scenario: Importing an existing custom rule missing a version field + +```Gherkin +Given the import payload contains an existing custom rule without a version field +When the user imports the rule +Then the rule should be updated +And the ruleSource type should be "internal" +And the "version" field should be set to the existing rule's "version" +``` + +#### Scenario: Importing a new custom rule missing a version field + +```Gherkin +Given the import payload contains a new custom rule without a version field +When the user imports the rule +Then the rule should be created +And the ruleSource type should be "internal" +And the "version" field should be set to 1 +``` + +#### Scenario: Importing a rule with overwrite flag set to true + +```Gherkin +Given the import payload contains a rule with an existing rule_id +And the overwrite flag is set to true +When the user imports the rule +Then the rule should be overwritten +And the ruleSource type should be calculated based on the rule_id and version +``` + +#### Scenario: Importing a rule with overwrite flag set to false + +```Gherkin +Given the import payload contains a rule with an existing rule_id +And the overwrite flag is set to false +When the user imports the rule +Then the import should be rejected with a message "rule_id already exists" +``` + +#### Scenario: Importing both custom and prebuilt rules + +```Gherkin +Given the import payload contains modified and unmodified, custom and prebuilt rules +When the user imports the rule +Then custom rules should be created or updated, with versions defaulted to 1 +And prebuilt rules should be created or updated, +And prebuilt rules missing versions should be rejected +``` diff --git a/x-pack/plugins/security_solution/public/app/actions/telemetry.test.ts b/x-pack/plugins/security_solution/public/app/actions/telemetry.test.ts index 9b22aa03fbea..28d4b90f4d9e 100644 --- a/x-pack/plugins/security_solution/public/app/actions/telemetry.test.ts +++ b/x-pack/plugins/security_solution/public/app/actions/telemetry.test.ts @@ -9,6 +9,7 @@ import type { StartServices } from '../../types'; import { enhanceActionWithTelemetry } from './telemetry'; import { createAction } from '@kbn/ui-actions-plugin/public'; import type { CellActionExecutionContext } from '@kbn/cell-actions'; +import { AppEventTypes } from '../../common/lib/telemetry'; const actionId = 'test_action_id'; const displayName = 'test-actions'; @@ -29,13 +30,13 @@ const context = { describe('enhanceActionWithTelemetry', () => { it('calls telemetry report when the action is executed', () => { - const telemetry = { reportCellActionClicked: jest.fn() }; + const telemetry = { reportEvent: jest.fn() }; const services = { telemetry } as unknown as StartServices; const enhancedAction = enhanceActionWithTelemetry(action, services); enhancedAction.execute(context); - expect(telemetry.reportCellActionClicked).toHaveBeenCalledWith({ + expect(telemetry.reportEvent).toHaveBeenCalledWith(AppEventTypes.CellActionClicked, { displayName, actionId, fieldName, diff --git a/x-pack/plugins/security_solution/public/app/actions/telemetry.ts b/x-pack/plugins/security_solution/public/app/actions/telemetry.ts index 319194e57f81..0c69f7b23366 100644 --- a/x-pack/plugins/security_solution/public/app/actions/telemetry.ts +++ b/x-pack/plugins/security_solution/public/app/actions/telemetry.ts @@ -9,6 +9,7 @@ import type { CellAction, CellActionExecutionContext } from '@kbn/cell-actions'; import type { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; import type { StartServices } from '../../types'; import type { SecurityCellActionExecutionContext } from './types'; +import { AppEventTypes } from '../../common/lib/telemetry'; export const enhanceActionWithTelemetry = ( action: CellAction, @@ -19,7 +20,7 @@ export const enhanceActionWithTelemetry = ( const enhancedExecute = ( context: ActionExecutionContext ): Promise => { - telemetry.reportCellActionClicked({ + telemetry.reportEvent(AppEventTypes.CellActionClicked, { actionId: rest.id, displayName: rest.getDisplayName(context), fieldName: context.data.map(({ field }) => field.name).join(', '), diff --git a/x-pack/plugins/security_solution/public/app/solution_navigation/links/app_links.ts b/x-pack/plugins/security_solution/public/app/solution_navigation/links/app_links.ts index f6a51f1d25f4..e0b9016f0e6b 100644 --- a/x-pack/plugins/security_solution/public/app/solution_navigation/links/app_links.ts +++ b/x-pack/plugins/security_solution/public/app/solution_navigation/links/app_links.ts @@ -8,11 +8,7 @@ import { SecurityPageName } from '@kbn/security-solution-navigation'; import { cloneDeep, remove, find } from 'lodash'; import type { AppLinkItems, LinkItem } from '../../../common/links/types'; -import { - createInvestigationsLinkFromNotes, - createInvestigationsLinkFromTimeline, - updateInvestigationsLinkFromNotes, -} from './sections/investigations_links'; +import { createInvestigationsLink, createTimelineLink } from './sections/investigations_links'; import { mlAppLink } from './sections/ml_links'; import { createAssetsLinkFromManage } from './sections/assets_links'; import { createSettingsLinksFromManage } from './sections/settings_links'; @@ -24,25 +20,6 @@ import { createSettingsLinksFromManage } from './sections/settings_links'; export const solutionAppLinksSwitcher = (appLinks: AppLinkItems): AppLinkItems => { const solutionAppLinks = cloneDeep(appLinks) as LinkItem[]; - // Remove timeline link - const [timelineLinkItem] = remove(solutionAppLinks, { id: SecurityPageName.timelines }); - if (timelineLinkItem) { - solutionAppLinks.push(createInvestigationsLinkFromTimeline(timelineLinkItem)); - } - - // Remove note link - const investigationsLinkItem = find(solutionAppLinks, { id: SecurityPageName.investigations }); - const [noteLinkItem] = remove(solutionAppLinks, { id: SecurityPageName.notes }); - if (noteLinkItem) { - if (!investigationsLinkItem) { - solutionAppLinks.push(createInvestigationsLinkFromNotes(noteLinkItem)); - } else { - solutionAppLinks.push( - updateInvestigationsLinkFromNotes(investigationsLinkItem, noteLinkItem) - ); - } - } - // Remove manage link const [manageLinkItem] = remove(solutionAppLinks, { id: SecurityPageName.administration }); @@ -51,6 +28,22 @@ export const solutionAppLinksSwitcher = (appLinks: AppLinkItems): AppLinkItems = solutionAppLinks.push(...createSettingsLinksFromManage(manageLinkItem)); } + // Create investigations link + const investigationsLinks = []; + const [timelineLinkItem] = remove(solutionAppLinks, { id: SecurityPageName.timelines }); + if (timelineLinkItem) { + investigationsLinks.push(createTimelineLink(timelineLinkItem)); + } + if (manageLinkItem) { + const noteLinkItem = find(manageLinkItem.links, { id: SecurityPageName.notes }); + if (noteLinkItem) { + investigationsLinks.push(noteLinkItem); + } + } + if (investigationsLinks.length > 0) { + solutionAppLinks.push(createInvestigationsLink(investigationsLinks)); + } + // Add ML link solutionAppLinks.push(mlAppLink); diff --git a/x-pack/plugins/security_solution/public/app/solution_navigation/links/sections/investigations_links.ts b/x-pack/plugins/security_solution/public/app/solution_navigation/links/sections/investigations_links.ts index 1e2fe4dc5cf3..ddcd88667d96 100644 --- a/x-pack/plugins/security_solution/public/app/solution_navigation/links/sections/investigations_links.ts +++ b/x-pack/plugins/security_solution/public/app/solution_navigation/links/sections/investigations_links.ts @@ -24,37 +24,16 @@ const investigationsAppLink: LinkItem = { links: [], // timeline and note links are added via the methods below }; -export const createInvestigationsLinkFromTimeline = (timelineLink: LinkItem): LinkItem => { - return { - ...investigationsAppLink, - links: [ - { ...timelineLink, description: i18n.TIMELINE_DESCRIPTION, landingIcon: IconTimelineLazy }, - ], - }; -}; - -export const createInvestigationsLinkFromNotes = (noteLink: LinkItem): LinkItem => { - return { - ...investigationsAppLink, - links: [{ ...noteLink, description: i18n.NOTE_DESCRIPTION, landingIcon: IconTimelineLazy }], - }; -}; +export const createInvestigationsLink = (links: LinkItem[]): LinkItem => ({ + ...investigationsAppLink, + links, +}); -export const updateInvestigationsLinkFromNotes = ( - investigationsLink: LinkItem, - noteLink: LinkItem -): LinkItem => { - const currentLinks = investigationsLink.links ?? []; - currentLinks.push({ - ...noteLink, - description: i18n.NOTE_DESCRIPTION, - landingIcon: 'filebeatApp', - }); - return { - ...investigationsLink, - links: currentLinks, - }; -}; +export const createTimelineLink = (timelineLink: LinkItem): LinkItem => ({ + ...timelineLink, + description: i18n.TIMELINE_DESCRIPTION, + landingIcon: IconTimelineLazy, +}); // navLinks define the navigation links for the Security Solution pages and External pages as well export const investigationsNavLinks: SolutionNavLink[] = [ diff --git a/x-pack/plugins/security_solution/public/app/solution_navigation/links/sections/investigations_translations.ts b/x-pack/plugins/security_solution/public/app/solution_navigation/links/sections/investigations_translations.ts index 931c3c20d400..55c6fe74f846 100644 --- a/x-pack/plugins/security_solution/public/app/solution_navigation/links/sections/investigations_translations.ts +++ b/x-pack/plugins/security_solution/public/app/solution_navigation/links/sections/investigations_translations.ts @@ -21,14 +21,6 @@ export const TIMELINE_DESCRIPTION = i18n.translate( } ); -export const NOTE_DESCRIPTION = i18n.translate( - 'xpack.securitySolution.navLinks.investigations.note.title', - { - defaultMessage: - 'Oversee, revise, and revisit the notes attached to alerts, events and Timelines.', - } -); - export const OSQUERY_TITLE = i18n.translate( 'xpack.securitySolution.navLinks.investigations.osquery.title', { diff --git a/x-pack/plugins/security_solution/public/app_links.ts b/x-pack/plugins/security_solution/public/app_links.ts index 481b58949ed2..dca76b1c37f7 100644 --- a/x-pack/plugins/security_solution/public/app_links.ts +++ b/x-pack/plugins/security_solution/public/app_links.ts @@ -6,7 +6,6 @@ */ import type { CoreStart } from '@kbn/core/public'; -import { links as notesLink } from './notes/links'; import { links as attackDiscoveryLinks } from './attack_discovery/links'; import type { AppLinkItems } from './common/links/types'; import { indicatorsLinks } from './threat_intelligence/links'; @@ -36,7 +35,6 @@ export const appLinks: AppLinkItems = Object.freeze([ rulesLinks, onboardingLinks, managementLinks, - notesLink, ]); export const getFilteredLinks = async ( @@ -57,6 +55,5 @@ export const getFilteredLinks = async ( rulesLinks, onboardingLinks, managementFilteredLinks, - notesLink, ]); }; diff --git a/x-pack/plugins/security_solution/public/assistant/use_assistant_telemetry/index.test.tsx b/x-pack/plugins/security_solution/public/assistant/use_assistant_telemetry/index.test.tsx index d714781ee11c..b90db333742a 100644 --- a/x-pack/plugins/security_solution/public/assistant/use_assistant_telemetry/index.test.tsx +++ b/x-pack/plugins/security_solution/public/assistant/use_assistant_telemetry/index.test.tsx @@ -9,6 +9,7 @@ import { renderHook } from '@testing-library/react-hooks'; import { useAssistantTelemetry } from '.'; import { BASE_SECURITY_CONVERSATIONS } from '../content/conversations'; import { createTelemetryServiceMock } from '../../common/lib/telemetry/telemetry_service.mock'; +import { AssistantEventTypes } from '../../common/lib/telemetry'; const customId = `My Convo`; const mockedConversations = { @@ -20,15 +21,9 @@ const mockedConversations = { messages: [], }, }; -const reportAssistantInvoked = jest.fn(); -const reportAssistantMessageSent = jest.fn(); -const reportAssistantQuickPrompt = jest.fn(); + const mockedTelemetry = { ...createTelemetryServiceMock(), - reportAssistantInvoked, - reportAssistantMessageSent, - reportAssistantQuickPrompt, - reportAssistantSettingToggled: () => {}, }; jest.mock('../../common/lib/kibana', () => { @@ -55,9 +50,9 @@ jest.mock('@kbn/elastic-assistant', () => ({ })); const trackingFns = [ - 'reportAssistantInvoked', - 'reportAssistantMessageSent', - 'reportAssistantQuickPrompt', + { name: 'reportAssistantInvoked', eventType: AssistantEventTypes.AssistantInvoked }, + { name: 'reportAssistantMessageSent', eventType: AssistantEventTypes.AssistantMessageSent }, + { name: 'reportAssistantQuickPrompt', eventType: AssistantEventTypes.AssistantQuickPrompt }, ]; describe('useAssistantTelemetry', () => { @@ -67,7 +62,7 @@ describe('useAssistantTelemetry', () => { it('should return the expected telemetry object with tracking functions', () => { const { result } = renderHook(() => useAssistantTelemetry()); trackingFns.forEach((fn) => { - expect(result.current).toHaveProperty(fn); + expect(result.current).toHaveProperty(fn.name); }); }); @@ -76,11 +71,11 @@ describe('useAssistantTelemetry', () => { const { result } = renderHook(() => useAssistantTelemetry()); const validId = Object.keys(mockedConversations)[0]; // @ts-ignore - const trackingFn = result.current[fn]; + const trackingFn = result.current[fn.name]; await trackingFn({ conversationId: validId, invokedBy: 'shortcut' }); // @ts-ignore - const trackingMockedFn = mockedTelemetry[fn]; - expect(trackingMockedFn).toHaveBeenCalledWith({ + const trackingMockedFn = mockedTelemetry.reportEvent; + expect(trackingMockedFn).toHaveBeenCalledWith(fn.eventType, { conversationId: validId, invokedBy: 'shortcut', }); @@ -89,11 +84,11 @@ describe('useAssistantTelemetry', () => { it('Should call tracking with "Custom" id when tracking is called with an isDefault=false conversation id', async () => { const { result } = renderHook(() => useAssistantTelemetry()); // @ts-ignore - const trackingFn = result.current[fn]; + const trackingFn = result.current[fn.name]; await trackingFn({ conversationId: customId, invokedBy: 'shortcut' }); // @ts-ignore - const trackingMockedFn = mockedTelemetry[fn]; - expect(trackingMockedFn).toHaveBeenCalledWith({ + const trackingMockedFn = mockedTelemetry.reportEvent; + expect(trackingMockedFn).toHaveBeenCalledWith(fn.eventType, { conversationId: 'Custom', invokedBy: 'shortcut', }); @@ -102,11 +97,11 @@ describe('useAssistantTelemetry', () => { it('Should call tracking with "Custom" id when tracking is called with an unknown conversation id', async () => { const { result } = renderHook(() => useAssistantTelemetry()); // @ts-ignore - const trackingFn = result.current[fn]; + const trackingFn = result.current[fn.name]; await trackingFn({ conversationId: '123', invokedBy: 'shortcut' }); // @ts-ignore - const trackingMockedFn = mockedTelemetry[fn]; - expect(trackingMockedFn).toHaveBeenCalledWith({ + const trackingMockedFn = mockedTelemetry.reportEvent; + expect(trackingMockedFn).toHaveBeenCalledWith(fn.eventType, { conversationId: 'Custom', invokedBy: 'shortcut', }); diff --git a/x-pack/plugins/security_solution/public/assistant/use_assistant_telemetry/index.tsx b/x-pack/plugins/security_solution/public/assistant/use_assistant_telemetry/index.tsx index 543eac554beb..04bfc8bdcd64 100644 --- a/x-pack/plugins/security_solution/public/assistant/use_assistant_telemetry/index.tsx +++ b/x-pack/plugins/security_solution/public/assistant/use_assistant_telemetry/index.tsx @@ -9,7 +9,13 @@ import { type AssistantTelemetry } from '@kbn/elastic-assistant'; import { useCallback } from 'react'; import { useKibana } from '../../common/lib/kibana'; import { useBaseConversations } from '../use_conversation_store'; - +import type { + ReportAssistantInvokedParams, + ReportAssistantMessageSentParams, + ReportAssistantQuickPromptParams, + ReportAssistantSettingToggledParams, +} from '../../common/lib/telemetry'; +import { AssistantEventTypes } from '../../common/lib/telemetry'; export const useAssistantTelemetry = (): AssistantTelemetry => { const { services: { telemetry }, @@ -27,27 +33,30 @@ export const useAssistantTelemetry = (): AssistantTelemetry => { const reportTelemetry = useCallback( async ({ - fn, + eventType, params: { conversationId, ...rest }, - }: // eslint-disable-next-line @typescript-eslint/no-explicit-any - any): Promise<{ - fn: keyof AssistantTelemetry; - params: AssistantTelemetry[keyof AssistantTelemetry]; - }> => - fn({ + }: { + eventType: AssistantEventTypes; + params: + | ReportAssistantInvokedParams + | ReportAssistantMessageSentParams + | ReportAssistantQuickPromptParams; + }) => + telemetry.reportEvent(eventType, { ...rest, conversationId: await getAnonymizedConversationTitle(conversationId), }), - [getAnonymizedConversationTitle] + [getAnonymizedConversationTitle, telemetry] ); return { - reportAssistantInvoked: (params) => - reportTelemetry({ fn: telemetry.reportAssistantInvoked, params }), - reportAssistantMessageSent: (params) => - reportTelemetry({ fn: telemetry.reportAssistantMessageSent, params }), - reportAssistantQuickPrompt: (params) => - reportTelemetry({ fn: telemetry.reportAssistantQuickPrompt, params }), - reportAssistantSettingToggled: (params) => telemetry.reportAssistantSettingToggled(params), + reportAssistantInvoked: (params: ReportAssistantInvokedParams) => + reportTelemetry({ eventType: AssistantEventTypes.AssistantInvoked, params }), + reportAssistantMessageSent: (params: ReportAssistantMessageSentParams) => + reportTelemetry({ eventType: AssistantEventTypes.AssistantMessageSent, params }), + reportAssistantQuickPrompt: (params: ReportAssistantQuickPromptParams) => + reportTelemetry({ eventType: AssistantEventTypes.AssistantQuickPrompt, params }), + reportAssistantSettingToggled: (params: ReportAssistantSettingToggledParams) => + telemetry.reportEvent(AssistantEventTypes.AssistantSettingToggled, params), }; }; diff --git a/x-pack/plugins/security_solution/public/cases/pages/index.test.tsx b/x-pack/plugins/security_solution/public/cases/pages/index.test.tsx deleted file mode 100644 index 94fc9063f042..000000000000 --- a/x-pack/plugins/security_solution/public/cases/pages/index.test.tsx +++ /dev/null @@ -1,101 +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 { Cases } from '.'; -import { Router } from '@kbn/shared-ux-router'; -import { render } from '@testing-library/react'; -import { TestProviders } from '../../common/mock'; -import { useTourContext } from '../../common/components/guided_onboarding_tour'; -import { - AlertsCasesTourSteps, - SecurityStepId, -} from '../../common/components/guided_onboarding_tour/tour_config'; - -jest.mock('../../common/components/guided_onboarding_tour'); -jest.mock('../../common/lib/kibana'); - -type Action = 'PUSH' | 'POP' | 'REPLACE'; -const pop: Action = 'POP'; -const location = { - pathname: '/network', - search: '', - state: '', - hash: '', -}; -const mockHistory = { - length: 2, - location, - action: pop, - push: jest.fn(), - replace: jest.fn(), - go: jest.fn(), - goBack: jest.fn(), - goForward: jest.fn(), - block: jest.fn(), - createHref: jest.fn(), - listen: jest.fn(), -}; - -describe('cases page in security', () => { - const endTourStep = jest.fn(); - beforeEach(() => { - (useTourContext as jest.Mock).mockReturnValue({ - activeStep: AlertsCasesTourSteps.viewCase, - incrementStep: () => null, - endTourStep, - isTourShown: () => true, - }); - jest.clearAllMocks(); - }); - - it('calls endTour on cases details page when SecurityStepId.alertsCases tour is active and step is AlertsCasesTourSteps.viewCase', () => { - render( - - - , - { wrapper: TestProviders } - ); - - expect(endTourStep).toHaveBeenCalledWith(SecurityStepId.alertsCases); - }); - - it('does not call endTour on cases details page when SecurityStepId.alertsCases tour is not active', () => { - (useTourContext as jest.Mock).mockReturnValue({ - activeStep: AlertsCasesTourSteps.viewCase, - incrementStep: () => null, - endTourStep, - isTourShown: () => false, - }); - render( - - - , - { wrapper: TestProviders } - ); - - expect(endTourStep).not.toHaveBeenCalled(); - }); - - it('does not call endTour on cases details page when SecurityStepId.alertsCases tour is active and step is not AlertsCasesTourSteps.viewCase', () => { - (useTourContext as jest.Mock).mockReturnValue({ - activeStep: AlertsCasesTourSteps.expandEvent, - incrementStep: () => null, - endTourStep, - isTourShown: () => true, - }); - - render( - - - , - { wrapper: TestProviders } - ); - - expect(endTourStep).not.toHaveBeenCalled(); - }); -}); diff --git a/x-pack/plugins/security_solution/public/cases/pages/index.tsx b/x-pack/plugins/security_solution/public/cases/pages/index.tsx index c873e48e4975..787dfc973c5d 100644 --- a/x-pack/plugins/security_solution/public/cases/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/pages/index.tsx @@ -5,22 +5,15 @@ * 2.0. */ -import React, { useCallback, useEffect, useMemo, useRef } from 'react'; +import React, { useCallback, useEffect, useRef } from 'react'; import { useDispatch } from 'react-redux'; import type { CaseViewRefreshPropInterface } from '@kbn/cases-plugin/common'; import { CaseMetricsFeature } from '@kbn/cases-plugin/common'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { CaseDetailsRefreshContext } from '../../common/components/endpoint'; import { DocumentDetailsRightPanelKey } from '../../flyout/document_details/shared/constants/panel_keys'; -import { useTourContext } from '../../common/components/guided_onboarding_tour'; -import { - AlertsCasesTourSteps, - SecurityStepId, -} from '../../common/components/guided_onboarding_tour/tour_config'; +import { RulePanelKey } from '../../flyout/rule_details/right'; import { TimelineId } from '../../../common/types/timeline'; - -import { getRuleDetailsUrl, useFormatUrl } from '../../common/components/link_to'; - import { useKibana, useNavigation } from '../../common/lib/kibana'; import { APP_ID, CASES_PATH, SecurityPageName } from '../../../common/constants'; import { timelineActions } from '../../timelines/store'; @@ -32,23 +25,15 @@ import * as timelineMarkdownPlugin from '../../common/components/markdown_editor import { useFetchAlertData } from './use_fetch_alert_data'; import { useUpsellingMessage } from '../../common/hooks/use_upselling'; import { useFetchNotes } from '../../notes/hooks/use_fetch_notes'; +import { DocumentEventTypes } from '../../common/lib/telemetry'; const CaseContainerComponent: React.FC = () => { const { cases, telemetry } = useKibana().services; const { getAppUrl, navigateTo } = useNavigation(); const userCasesPermissions = cases.helpers.canUseCases([APP_ID]); const dispatch = useDispatch(); - const { formatUrl: detectionsFormatUrl, search: detectionsUrlSearch } = useFormatUrl( - SecurityPageName.rules - ); const { openFlyout } = useExpandableFlyoutApi(); - const getDetectionsRuleDetailsHref = useCallback( - (ruleId: string | null | undefined) => - detectionsFormatUrl(getRuleDetailsUrl(ruleId ?? '', detectionsUrlSearch)), - [detectionsFormatUrl, detectionsUrlSearch] - ); - const interactionsUpsellingMessage = useUpsellingMessage('investigation_guide_interactions'); const showAlertDetails = useCallback( @@ -63,7 +48,7 @@ const CaseContainerComponent: React.FC = () => { }, }, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: TimelineId.casePage, panel: 'right', }); @@ -71,6 +56,15 @@ const CaseContainerComponent: React.FC = () => { [openFlyout, telemetry] ); + const onRuleDetailsClick = useCallback( + (ruleId: string | null | undefined) => { + if (ruleId) { + openFlyout({ right: { id: RulePanelKey, params: { ruleId } } }); + } + }, + [openFlyout] + ); + const { onLoad: onAlertsTableLoaded } = useFetchNotes(); const endpointDetailsHref = (endpointId: string) => @@ -82,16 +76,6 @@ const CaseContainerComponent: React.FC = () => { }); const refreshRef = useRef(null); - const { activeStep, endTourStep, isTourShown } = useTourContext(); - - const isTourActive = useMemo( - () => activeStep === AlertsCasesTourSteps.viewCase && isTourShown(SecurityStepId.alertsCases), - [activeStep, isTourShown] - ); - - useEffect(() => { - if (isTourActive) endTourStep(SecurityStepId.alertsCases); - }, [endTourStep, isTourActive]); useEffect(() => { dispatch( @@ -138,16 +122,7 @@ const CaseContainerComponent: React.FC = () => { }, }, ruleDetailsNavigation: { - href: getDetectionsRuleDetailsHref, - onClick: async (ruleId: string | null | undefined, e) => { - if (e) { - e.preventDefault(); - } - return navigateTo({ - deepLinkId: SecurityPageName.rules, - path: getRuleDetailsUrl(ruleId ?? ''), - }); - }, + onClick: onRuleDetailsClick, }, showAlertDetails, timelineIntegration: { diff --git a/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx b/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx index 5ec3e0c2d0e3..a56010182f13 100644 --- a/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.tsx @@ -19,12 +19,13 @@ import type { SetEventsLoading, ControlColumnProps, } from '../../../../../common/types'; -import { getMappedNonEcsValue } from '../../../../timelines/components/timeline/body/data_driven_columns'; import type { TimelineItem, TimelineNonEcsData } from '../../../../../common/search_strategy'; import type { ColumnHeaderOptions, OnRowSelected } from '../../../../../common/types/timeline'; import { useIsExperimentalFeatureEnabled } from '../../../hooks/use_experimental_features'; import { useTourContext } from '../../guided_onboarding_tour'; import { AlertsCasesTourSteps, SecurityStepId } from '../../guided_onboarding_tour/tour_config'; +import { NotesEventTypes, DocumentEventTypes } from '../../../lib/telemetry'; +import { getMappedNonEcsValue } from '../../../utils/get_mapped_non_ecs_value'; export type RowActionProps = EuiDataGridCellValueElementProps & { columnHeaders: ColumnHeaderOptions[]; @@ -109,7 +110,7 @@ const RowActionComponent = ({ }, }, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: tableId, panel: 'right', }); @@ -137,10 +138,10 @@ const RowActionComponent = ({ }, }, }); - telemetry.reportOpenNoteInExpandableFlyoutClicked({ + telemetry.reportEvent(NotesEventTypes.OpenNoteInExpandableFlyoutClicked, { location: tableId, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: tableId, panel: 'left', }); diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx index b86f65e020a1..adae56f75227 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx @@ -36,7 +36,6 @@ import type { EuiTheme } from '@kbn/kibana-react-plugin/common'; import type { EuiDataGridRowHeightsOptions } from '@elastic/eui'; import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy'; import { ALERTS_TABLE_VIEW_SELECTION_KEY } from '../../../../common/constants'; -import type { Sort } from '../../../timelines/components/timeline/body/sort'; import type { ControlColumnProps, OnRowSelected, @@ -44,7 +43,7 @@ import type { SetEventsDeleted, SetEventsLoading, } from '../../../../common/types'; -import type { RowRenderer } from '../../../../common/types/timeline'; +import type { RowRenderer, SortColumnTimeline as Sort } from '../../../../common/types/timeline'; import { InputsModelId } from '../../store/inputs/constants'; import type { State } from '../../store'; import { inputsActions } from '../../store/actions'; diff --git a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour.test.tsx b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour.test.tsx index cb99772343c7..e3f85df557e8 100644 --- a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour.test.tsx @@ -104,8 +104,8 @@ describe('useTourContext', () => { wrapper: TourContextProvider, }); await waitForNextUpdate(); - result.current.setStep(tourId, 7); - expect(result.current.activeStep).toBe(7); + result.current.setStep(tourId, 6); + expect(result.current.activeStep).toBe(6); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_config.ts b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_config.ts index dd04b76d061a..31080d7ea49f 100644 --- a/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_config.ts +++ b/x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour/tour_config.ts @@ -22,7 +22,6 @@ export enum AlertsCasesTourSteps { addAlertToCase = 4, createCase = 5, submitCase = 6, - viewCase = 7, } export type StepConfig = Pick< @@ -72,7 +71,6 @@ export const hiddenWhenCaseFlyoutExpanded: Record { }); const mockCall = { ...mockTourStep.mock.calls[0][0] }; expect(mockCall.step).toEqual(1); - expect(mockCall.stepsTotal).toEqual(7); + expect(mockCall.stepsTotal).toEqual(6); }); it('forces the render for createCase step of the SecurityStepId.alertsCases tour step', () => { diff --git a/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.tsx b/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.tsx index 1341cb72104d..db88061d8601 100644 --- a/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.tsx +++ b/x-pack/plugins/security_solution/public/common/components/header_actions/header_actions.tsx @@ -10,9 +10,9 @@ import { EuiButtonIcon, EuiToolTip, EuiCheckbox } from '@elastic/eui'; import { useDispatch } from 'react-redux'; import styled from 'styled-components'; +import { isFullScreen } from '../../../timelines/components/timeline/helpers'; import type { HeaderActionProps } from '../../../../common/types'; import { TimelineId } from '../../../../common/types'; -import { isFullScreen } from '../../../timelines/components/timeline/body/column_headers'; import { isActiveTimeline } from '../../../helpers'; import { getColumnHeader } from '../../../timelines/components/timeline/body/column_headers/helpers'; import { timelineActions } from '../../../timelines/store'; diff --git a/x-pack/plugins/security_solution/public/common/components/links/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/links/index.test.tsx index dad30ee050dd..ab5507b958e2 100644 --- a/x-pack/plugins/security_solution/public/common/components/links/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/links/index.test.tsx @@ -10,10 +10,7 @@ import { mount, shallow } from 'enzyme'; import React from 'react'; import { removeExternalLinkText } from '@kbn/securitysolution-io-ts-utils'; import { mountWithIntl } from '@kbn/test-jest-helpers'; - import { encodeIpv6 } from '../../lib/helpers'; -import { useUiSetting$ } from '../../lib/kibana'; - import { GoogleLink, HostDetailsLink, @@ -26,16 +23,33 @@ import { DEFAULT_NUMBER_OF_LINK, ExternalLink, SecuritySolutionLinkButton, + CaseDetailsLink, } from '.'; import { SecurityPageName } from '../../../app/types'; import { mockGetAppUrl, mockNavigateTo } from '@kbn/security-solution-navigation/mocks/navigation'; +import { APP_UI_ID } from '../../../../common'; jest.mock('@kbn/security-solution-navigation/src/navigation'); jest.mock('../navigation/use_url_state_query_params'); - jest.mock('../../../overview/components/events_by_dataset'); -jest.mock('../../lib/kibana'); +const mockNavigateToApp = jest.fn(); +const mockUseUiSetting$ = jest.fn(); +jest.mock('../../lib/kibana', () => { + const original = jest.requireActual('../../lib/kibana'); + return { + ...original, + useKibana: () => ({ + services: { + ...original.useKibana().services, + application: { + navigateToApp: mockNavigateToApp, + }, + }, + }), + useUiSetting$: () => mockUseUiSetting$(), + }; +}); mockGetAppUrl.mockImplementation(({ path }) => path); @@ -96,6 +110,55 @@ describe('Custom Links', () => { }); }); + describe('CaseDetailsLink', () => { + test('should render a link with detailName as displayed text', () => { + const wrapper = mountWithIntl(); + expect(wrapper.text()).toEqual('name'); + expect(wrapper.find('EuiLink').last().prop('aria-label')).toEqual( + 'click to visit case with title name' + ); + expect(wrapper.find('EuiLink').last().prop('href')).toEqual('/name'); + }); + + test('should render a link with children instead of detailName', () => { + const wrapper = mountWithIntl( + +
    {'children'}
    +
    + ); + expect(wrapper.text()).toEqual('children'); + }); + + test('should render a link with aria-label using title prop instead of detailName', () => { + const wrapper = mountWithIntl(); + expect(wrapper.find('EuiLink').last().prop('aria-label')).toEqual( + 'click to visit case with title title' + ); + }); + + it('should call navigateToApp with correct values', () => { + const wrapper = mountWithIntl(); + wrapper.find('a[href="/name"]').simulate('click'); + + expect(mockNavigateToApp).toHaveBeenCalledWith(APP_UI_ID, { + deepLinkId: SecurityPageName.case, + path: '/name', + openInNewTab: false, + }); + }); + + it('should call navigateToApp with value of openInNewTab prop', () => { + const wrapper = mountWithIntl(); + wrapper.find('a[href="/name"]').simulate('click'); + + expect(mockNavigateToApp).toHaveBeenCalledWith(APP_UI_ID, { + deepLinkId: SecurityPageName.case, + path: '/name', + openInNewTab: true, + }); + }); + }); + describe('GoogleLink', () => { test('it renders text passed in as value', () => { const wrapper = mountWithIntl( @@ -309,8 +372,7 @@ describe('Custom Links', () => { describe('links property', () => { beforeEach(() => { - (useUiSetting$ as jest.Mock).mockReset(); - (useUiSetting$ as jest.Mock).mockReturnValue([mockDefaultReputationLinks]); + mockUseUiSetting$.mockReturnValue([mockDefaultReputationLinks]); }); test('it renders default link text', () => { @@ -321,8 +383,7 @@ describe('Custom Links', () => { }); test('it renders customized link text', () => { - (useUiSetting$ as jest.Mock).mockReset(); - (useUiSetting$ as jest.Mock).mockReturnValue([mockCustomizedReputationLinks]); + mockUseUiSetting$.mockReturnValue([mockCustomizedReputationLinks]); const wrapper = shallow(); wrapper.find('[data-test-subj="externalLink"]').forEach((node, idx) => { expect(node.at(idx).text()).toEqual(mockCustomizedReputationLinks[idx].name); @@ -341,12 +402,7 @@ describe('Custom Links', () => { describe('number of links', () => { beforeAll(() => { - (useUiSetting$ as jest.Mock).mockReset(); - (useUiSetting$ as jest.Mock).mockReturnValue([mockCustomizedReputationLinks]); - }); - - afterEach(() => { - (useUiSetting$ as jest.Mock).mockClear(); + mockUseUiSetting$.mockReturnValue([mockCustomizedReputationLinks]); }); test('it renders correct number of links by default', () => { @@ -364,8 +420,7 @@ describe('Custom Links', () => { }); test('it renders correct number of visible link', () => { - (useUiSetting$ as jest.Mock).mockReset(); - (useUiSetting$ as jest.Mock).mockReturnValue([mockCustomizedReputationLinks]); + mockUseUiSetting$.mockReturnValue([mockCustomizedReputationLinks]); const wrapper = mountWithIntl( @@ -374,8 +429,7 @@ describe('Custom Links', () => { }); test('it renders correct number of tooltips for visible links', () => { - (useUiSetting$ as jest.Mock).mockReset(); - (useUiSetting$ as jest.Mock).mockReturnValue([mockCustomizedReputationLinks]); + mockUseUiSetting$.mockReturnValue([mockCustomizedReputationLinks]); const wrapper = mountWithIntl( @@ -391,12 +445,9 @@ describe('Custom Links', () => { ]; const mockInvalidLinksNoUrl = [{ name: 'Link 1' }]; const mockInvalidUrl = [{ name: 'Link 1', url_template: "" }]; - afterEach(() => { - (useUiSetting$ as jest.Mock).mockReset(); - }); test('it filters empty object', () => { - (useUiSetting$ as jest.Mock).mockReturnValue([mockInvalidLinksEmptyObj]); + mockUseUiSetting$.mockReturnValue([mockInvalidLinksEmptyObj]); const wrapper = mountWithIntl( @@ -405,7 +456,7 @@ describe('Custom Links', () => { }); test('it filters object without name property', () => { - (useUiSetting$ as jest.Mock).mockReturnValue([mockInvalidLinksNoName]); + mockUseUiSetting$.mockReturnValue([mockInvalidLinksNoName]); const wrapper = mountWithIntl( @@ -414,7 +465,7 @@ describe('Custom Links', () => { }); test('it filters object without url_template property', () => { - (useUiSetting$ as jest.Mock).mockReturnValue([mockInvalidLinksNoUrl]); + mockUseUiSetting$.mockReturnValue([mockInvalidLinksNoUrl]); const wrapper = mountWithIntl( @@ -423,7 +474,7 @@ describe('Custom Links', () => { }); test('it filters object with invalid url', () => { - (useUiSetting$ as jest.Mock).mockReturnValue([mockInvalidUrl]); + mockUseUiSetting$.mockReturnValue([mockInvalidUrl]); const wrapper = mountWithIntl( @@ -434,12 +485,7 @@ describe('Custom Links', () => { describe('external icon', () => { beforeAll(() => { - (useUiSetting$ as jest.Mock).mockReset(); - (useUiSetting$ as jest.Mock).mockReturnValue([mockCustomizedReputationLinks]); - }); - - afterEach(() => { - (useUiSetting$ as jest.Mock).mockClear(); + mockUseUiSetting$.mockReturnValue([mockCustomizedReputationLinks]); }); test('it renders correct number of external icons by default', () => { diff --git a/x-pack/plugins/security_solution/public/common/components/links/index.tsx b/x-pack/plugins/security_solution/public/common/components/links/index.tsx index 9d615d80be63..83042c2f4fbf 100644 --- a/x-pack/plugins/security_solution/public/common/components/links/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/links/index.tsx @@ -8,11 +8,9 @@ import type { EuiButtonEmpty, EuiButtonIcon } from '@elastic/eui'; import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiToolTip } from '@elastic/eui'; import type { SyntheticEvent, MouseEvent } from 'react'; -import React, { useMemo, useCallback, useEffect } from 'react'; +import React, { useMemo, useCallback } from 'react'; import { isArray, isNil } from 'lodash/fp'; -import { GuidedOnboardingTourStep } from '../guided_onboarding_tour/tour_step'; -import { AlertsCasesTourSteps, SecurityStepId } from '../guided_onboarding_tour/tour_config'; -import { useTourContext } from '../guided_onboarding_tour'; +import type { NavigateToAppOptions } from '@kbn/core-application-browser'; import { IP_REPUTATION_LINKS_SETTING, APP_UI_ID } from '../../../../common/constants'; import { encodeIpv6 } from '../../lib/helpers'; import { @@ -43,6 +41,7 @@ import { import type { HostsTableType } from '../../../explore/hosts/store/model'; import type { UsersTableType } from '../../../explore/users/store/model'; import { useGetSecuritySolutionLinkProps, withSecuritySolutionLink } from './link_props'; +import { EntityEventTypes } from '../../lib/telemetry'; export { useSecuritySolutionLinkProps, type GetSecuritySolutionLinkProps } from './link_props'; export { LinkButton, LinkAnchor } from './helpers'; @@ -96,7 +95,7 @@ const UserDetailsLinkComponent: React.FC<{ const onClick = useCallback( (e: SyntheticEvent) => { - telemetry.reportEntityDetailsClicked({ entity: 'user' }); + telemetry.reportEvent(EntityEventTypes.EntityDetailsClicked, { entity: 'user' }); const callback = onClickParam ?? goToUsersDetails; callback(e); }, @@ -173,7 +172,7 @@ const HostDetailsLinkComponent: React.FC = ({ const onClick = useCallback( (e: SyntheticEvent) => { - telemetry.reportEntityDetailsClicked({ entity: 'host' }); + telemetry.reportEvent(EntityEventTypes.EntityDetailsClicked, { entity: 'host' }); const callback = onClickParam ?? goToHostDetails; callback(e); @@ -306,27 +305,19 @@ export interface CaseDetailsLinkComponentProps { */ title?: string; /** - * Link index + * If true, will open the app in new tab, will share session information via window.open if base */ - index?: number; + openInNewTab?: NavigateToAppOptions['openInNewTab']; } const CaseDetailsLinkComponent: React.FC = ({ - index, children, detailName, title, + openInNewTab = false, }) => { const { formatUrl, search } = useFormatUrl(SecurityPageName.case); const { navigateToApp } = useKibana().services.application; - const { activeStep, isTourShown } = useTourContext(); - const isTourStepActive = useMemo( - () => - activeStep === AlertsCasesTourSteps.viewCase && - isTourShown(SecurityStepId.alertsCases) && - index === 0, - [activeStep, index, isTourShown] - ); const goToCaseDetails = useCallback( async (ev?: SyntheticEvent) => { @@ -334,32 +325,21 @@ const CaseDetailsLinkComponent: React.FC = ({ return navigateToApp(APP_UI_ID, { deepLinkId: SecurityPageName.case, path: getCaseDetailsUrl({ id: detailName, search }), + openInNewTab, }); }, - [detailName, navigateToApp, search] + [detailName, navigateToApp, openInNewTab, search] ); - useEffect(() => { - if (isTourStepActive) - document.querySelector(`[tour-step="RelatedCases-accordion"]`)?.scrollIntoView(); - }, [isTourStepActive]); - return ( - - - {children ? children : detailName} - - + {children ? children : detailName} + ); }; export const CaseDetailsLink = React.memo(CaseDetailsLinkComponent); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx index 0801ec37f6ae..5d1d2ab2eaba 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx @@ -11,7 +11,7 @@ import { TestProviders } from '../../../mock'; import type { SecurityJob } from '../types'; import { createTelemetryServiceMock } from '../../../lib/telemetry/telemetry_service.mock'; -import { ML_JOB_TELEMETRY_STATUS } from '../../../lib/telemetry'; +import { ML_JOB_TELEMETRY_STATUS, EntityEventTypes } from '../../../lib/telemetry'; const wrapper = ({ children }: { children: React.ReactNode }) => ( {children} @@ -188,14 +188,14 @@ describe('useSecurityJobsHelpers', () => { await result.current.enableDatafeed(JOB, TIMESTAMP); }); - expect(mockedTelemetry.reportMLJobUpdate).toHaveBeenCalledWith({ + expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith(EntityEventTypes.MLJobUpdate, { status: ML_JOB_TELEMETRY_STATUS.moduleInstalled, isElasticJob: true, jobId, moduleId, }); - expect(mockedTelemetry.reportMLJobUpdate).toHaveBeenCalledWith({ + expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith(EntityEventTypes.MLJobUpdate, { status: ML_JOB_TELEMETRY_STATUS.started, isElasticJob: true, jobId, @@ -211,7 +211,7 @@ describe('useSecurityJobsHelpers', () => { await result.current.enableDatafeed({ ...JOB, isInstalled: true }, TIMESTAMP); }); - expect(mockedTelemetry.reportMLJobUpdate).toHaveBeenCalledWith({ + expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith(EntityEventTypes.MLJobUpdate, { status: ML_JOB_TELEMETRY_STATUS.startError, errorMessage: 'Start job failure - test_error', isElasticJob: true, @@ -228,7 +228,7 @@ describe('useSecurityJobsHelpers', () => { await result.current.enableDatafeed(JOB, TIMESTAMP); }); - expect(mockedTelemetry.reportMLJobUpdate).toHaveBeenCalledWith({ + expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith(EntityEventTypes.MLJobUpdate, { status: ML_JOB_TELEMETRY_STATUS.installationError, errorMessage: 'Create job failure - test_error', isElasticJob: true, @@ -295,7 +295,7 @@ describe('useSecurityJobsHelpers', () => { await result.current.disableDatafeed({ ...JOB, isInstalled: true }); }); - expect(mockedTelemetry.reportMLJobUpdate).toHaveBeenCalledWith({ + expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith(EntityEventTypes.MLJobUpdate, { status: ML_JOB_TELEMETRY_STATUS.stopped, isElasticJob: true, jobId, @@ -311,7 +311,7 @@ describe('useSecurityJobsHelpers', () => { await result.current.disableDatafeed({ ...JOB, isInstalled: true }); }); - expect(mockedTelemetry.reportMLJobUpdate).toHaveBeenCalledWith({ + expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith(EntityEventTypes.MLJobUpdate, { status: ML_JOB_TELEMETRY_STATUS.stopError, errorMessage: 'Stop job failure - test_error', isElasticJob: true, diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.ts b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.ts index 393e132436c3..ab966770aaf3 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.ts @@ -13,6 +13,7 @@ import { METRIC_TYPE, ML_JOB_TELEMETRY_STATUS, TELEMETRY_EVENT, + EntityEventTypes, track, } from '../../../lib/telemetry'; @@ -43,7 +44,7 @@ export const useEnableDataFeed = () => { jobIdErrorFilter: [job.id], groups: job.groups, }); - telemetry.reportMLJobUpdate({ + telemetry.reportEvent(EntityEventTypes.MLJobUpdate, { jobId: job.id, isElasticJob: job.isElasticJob, moduleId: job.moduleId, @@ -52,7 +53,7 @@ export const useEnableDataFeed = () => { } catch (error) { setIsLoading(false); addError(error, { title: i18n.CREATE_JOB_FAILURE }); - telemetry.reportMLJobUpdate({ + telemetry.reportEvent(EntityEventTypes.MLJobUpdate, { jobId: job.id, isElasticJob: job.isElasticJob, moduleId: job.moduleId, @@ -82,7 +83,7 @@ export const useEnableDataFeed = () => { throw new Error(response[datafeedId].error); } - telemetry.reportMLJobUpdate({ + telemetry.reportEvent(EntityEventTypes.MLJobUpdate, { jobId: job.id, isElasticJob: job.isElasticJob, status: ML_JOB_TELEMETRY_STATUS.started, @@ -92,7 +93,7 @@ export const useEnableDataFeed = () => { } catch (error) { track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.JOB_ENABLE_FAILURE); addError(error, { title: i18n.START_JOB_FAILURE }); - telemetry.reportMLJobUpdate({ + telemetry.reportEvent(EntityEventTypes.MLJobUpdate, { jobId: job.id, isElasticJob: job.isElasticJob, status: ML_JOB_TELEMETRY_STATUS.startError, @@ -124,7 +125,7 @@ export const useEnableDataFeed = () => { throw new Error(response.error); } - telemetry.reportMLJobUpdate({ + telemetry.reportEvent(EntityEventTypes.MLJobUpdate, { jobId: job.id, isElasticJob: job.isElasticJob, status: ML_JOB_TELEMETRY_STATUS.stopped, @@ -134,7 +135,7 @@ export const useEnableDataFeed = () => { } catch (error) { track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.JOB_DISABLE_FAILURE); addError(error, { title: i18n.STOP_JOB_FAILURE }); - telemetry.reportMLJobUpdate({ + telemetry.reportEvent(EntityEventTypes.MLJobUpdate, { jobId: job.id, isElasticJob: job.isElasticJob, status: ML_JOB_TELEMETRY_STATUS.stopError, diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/use_breadcrumbs_nav.test.ts b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/use_breadcrumbs_nav.test.ts index c8c675f0f40a..c20d1f4623fa 100644 --- a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/use_breadcrumbs_nav.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/use_breadcrumbs_nav.test.ts @@ -137,12 +137,12 @@ describe('useBreadcrumbsNav', () => { }); it('should create breadcrumbs onClick handler', () => { - const reportBreadcrumbClickedMock = jest.fn(); + const reportEventMock = jest.fn(); (kibanaLib.useKibana as jest.Mock).mockImplementation(() => ({ services: { telemetry: { - reportBreadcrumbClicked: reportBreadcrumbClickedMock, + reportEvent: reportEventMock, }, }, })); @@ -157,6 +157,6 @@ describe('useBreadcrumbsNav', () => { expect(event.preventDefault).toHaveBeenCalled(); expect(mockDispatch).toHaveBeenCalled(); - expect(reportBreadcrumbClickedMock).toHaveBeenCalled(); + expect(reportEventMock).toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/use_breadcrumbs_nav.ts b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/use_breadcrumbs_nav.ts index 7825435fafca..aae96ddd07dc 100644 --- a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/use_breadcrumbs_nav.ts +++ b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/use_breadcrumbs_nav.ts @@ -16,7 +16,7 @@ import { timelineActions } from '../../../../timelines/store'; import { TimelineId } from '../../../../../common/types/timeline'; import type { GetSecuritySolutionUrl } from '../../link_to'; import { useGetSecuritySolutionUrl } from '../../link_to'; -import type { TelemetryClientStart } from '../../../lib/telemetry'; +import { AppEventTypes, type TelemetryServiceStart } from '../../../lib/telemetry'; import { useKibana, useNavigateTo, type NavigateTo } from '../../../lib/kibana'; import { useRouteSpy } from '../../../utils/route/use_route_spy'; import { updateBreadcrumbsNav } from '../../../breadcrumbs'; @@ -68,7 +68,7 @@ const addOnClicksHandlers = ( breadcrumbs: ChromeBreadcrumb[], dispatch: Dispatch, navigateTo: NavigateTo, - telemetry: TelemetryClientStart + telemetry: TelemetryServiceStart ): ChromeBreadcrumb[] => breadcrumbs.map((breadcrumb) => ({ ...breadcrumb, @@ -89,13 +89,13 @@ const createOnClickHandler = href: string, dispatch: Dispatch, navigateTo: NavigateTo, - telemetry: TelemetryClientStart, + telemetry: TelemetryServiceStart, title: React.ReactNode ) => (ev: SyntheticEvent) => { ev.preventDefault(); if (typeof title === 'string') { - telemetry.reportBreadcrumbClicked({ title }); + telemetry.reportEvent(AppEventTypes.BreadcrumbClicked, { title }); } dispatch(timelineActions.showTimeline({ id: TimelineId.active, show: false })); navigateTo({ url: href }); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx index f1f86c77202c..b7f2879f4505 100644 --- a/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/entry_item.tsx @@ -9,7 +9,7 @@ import React, { useCallback, useMemo } from 'react'; import { EuiFormRow, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import styled from 'styled-components'; -import { FieldComponent } from '@kbn/securitysolution-autocomplete'; +import { EsFieldSelector } from '@kbn/securitysolution-autocomplete'; import type { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; import type { FormattedEntry, Entry } from './types'; import * as i18n from './translations'; @@ -57,7 +57,7 @@ export const EntryItem: React.FC = ({ const renderFieldInput = useMemo(() => { const comboBox = ( - = ({ const renderThreatFieldInput = useMemo(() => { const comboBox = ( - ; - } - | { - eventType: TelemetryEventTypes.AssistantSettingToggled; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.AssistantMessageSent; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.AssistantQuickPrompt; - schema: RootSchema; - }; +export interface AssistantTelemetryEventsMap { + [AssistantEventTypes.AssistantInvoked]: ReportAssistantInvokedParams; + [AssistantEventTypes.AssistantMessageSent]: ReportAssistantMessageSentParams; + [AssistantEventTypes.AssistantQuickPrompt]: ReportAssistantQuickPromptParams; + [AssistantEventTypes.AssistantSettingToggled]: ReportAssistantSettingToggledParams; +} + +export interface AssistantTelemetryEvent { + eventType: AssistantEventTypes; + schema: RootSchema; +} diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/alerts_grouping/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/alerts_grouping/index.ts index 7c990dc75776..3e2119205b77 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/alerts_grouping/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/alerts_grouping/index.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { TelemetryEvent } from '../../types'; -import { TelemetryEventTypes } from '../../constants'; +import type { AlertsGroupingTelemetryEvent } from './types'; +import { AlertsEventTypes } from './types'; -export const alertsGroupingToggledEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.AlertsGroupingToggled, +export const alertsGroupingToggledEvent: AlertsGroupingTelemetryEvent = { + eventType: AlertsEventTypes.AlertsGroupingToggled, schema: { isOpen: { type: 'boolean', @@ -35,8 +35,8 @@ export const alertsGroupingToggledEvent: TelemetryEvent = { }, }; -export const alertsGroupingChangedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.AlertsGroupingChanged, +export const alertsGroupingChangedEvent: AlertsGroupingTelemetryEvent = { + eventType: AlertsEventTypes.AlertsGroupingChanged, schema: { tableId: { type: 'keyword', @@ -55,8 +55,8 @@ export const alertsGroupingChangedEvent: TelemetryEvent = { }, }; -export const alertsGroupingTakeActionEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.AlertsGroupingTakeAction, +export const alertsGroupingTakeActionEvent: AlertsGroupingTelemetryEvent = { + eventType: AlertsEventTypes.AlertsGroupingTakeAction, schema: { tableId: { type: 'keyword', @@ -88,3 +88,9 @@ export const alertsGroupingTakeActionEvent: TelemetryEvent = { }, }, }; + +export const alertsTelemetryEvents = [ + alertsGroupingToggledEvent, + alertsGroupingChangedEvent, + alertsGroupingTakeActionEvent, +]; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/alerts_grouping/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/alerts_grouping/types.ts index d2b5e227ee66..924ddd4d1987 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/alerts_grouping/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/alerts_grouping/types.ts @@ -6,41 +6,38 @@ */ import type { RootSchema } from '@kbn/core/public'; -import type { TelemetryEventTypes } from '../../constants'; -export interface ReportAlertsGroupingChangedParams { +export enum AlertsEventTypes { + AlertsGroupingChanged = 'Alerts Grouping Changed', + AlertsGroupingToggled = 'Alerts Grouping Toggled', + AlertsGroupingTakeAction = 'Alerts Grouping Take Action', +} + +interface ReportAlertsGroupingChangedParams { tableId: string; groupByField: string; } -export interface ReportAlertsGroupingToggledParams { +interface ReportAlertsGroupingToggledParams { isOpen: boolean; tableId: string; groupNumber: number; } -export interface ReportAlertsTakeActionParams { +interface ReportAlertsTakeActionParams { tableId: string; groupNumber: number; status: 'open' | 'closed' | 'acknowledged'; groupByField: string; } -export type ReportAlertsGroupingTelemetryEventParams = - | ReportAlertsGroupingChangedParams - | ReportAlertsGroupingToggledParams - | ReportAlertsTakeActionParams; +export interface AlertsGroupingTelemetryEventsMap { + [AlertsEventTypes.AlertsGroupingChanged]: ReportAlertsGroupingChangedParams; + [AlertsEventTypes.AlertsGroupingToggled]: ReportAlertsGroupingToggledParams; + [AlertsEventTypes.AlertsGroupingTakeAction]: ReportAlertsTakeActionParams; +} -export type AlertsGroupingTelemetryEvent = - | { - eventType: TelemetryEventTypes.AlertsGroupingToggled; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.AlertsGroupingChanged; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.AlertsGroupingTakeAction; - schema: RootSchema; - }; +export interface AlertsGroupingTelemetryEvent { + eventType: AlertsEventTypes; + schema: RootSchema; +} diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/app/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/app/index.ts new file mode 100644 index 000000000000..d00d1df5f830 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/app/index.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { AppTelemetryEvent } from './types'; +import { AppEventTypes } from './types'; + +const cellActionClickedEvent: AppTelemetryEvent = { + eventType: AppEventTypes.CellActionClicked, + schema: { + fieldName: { + type: 'keyword', + _meta: { + description: 'Field Name', + optional: false, + }, + }, + actionId: { + type: 'keyword', + _meta: { + description: 'Action id', + optional: false, + }, + }, + displayName: { + type: 'keyword', + _meta: { + description: 'User friendly action name', + optional: false, + }, + }, + metadata: { + type: 'pass_through', + _meta: { + description: 'Action metadata', + optional: true, + }, + }, + }, +}; + +const breadCrumbClickedEvent: AppTelemetryEvent = { + eventType: AppEventTypes.BreadcrumbClicked, + schema: { + title: { + type: 'keyword', + _meta: { + description: 'Breadcrumb title', + optional: false, + }, + }, + }, +}; + +export const appTelemetryEvents = [cellActionClickedEvent, breadCrumbClickedEvent]; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/app/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/app/types.ts new file mode 100644 index 000000000000..f42e689cc3fd --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/app/types.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 { RootSchema } from '@kbn/core/public'; +import type { SecurityCellActionMetadata } from '../../../../../app/actions/types'; + +export enum AppEventTypes { + CellActionClicked = 'Cell Action Clicked', + BreadcrumbClicked = 'Breadcrumb Clicked', +} + +interface ReportCellActionClickedParams { + metadata: SecurityCellActionMetadata | undefined; + displayName: string; + actionId: string; + fieldName: string; +} + +interface ReportBreadcrumbClickedParams { + title: string; +} + +export interface AppTelemetryEventsMap { + [AppEventTypes.CellActionClicked]: ReportCellActionClickedParams; + [AppEventTypes.BreadcrumbClicked]: ReportBreadcrumbClickedParams; +} + +export interface AppTelemetryEvent { + eventType: AppEventTypes; + schema: RootSchema; +} diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/data_quality/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/data_quality/index.ts index 1a3a88cbd2f5..16e8a3e1eaa6 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/data_quality/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/data_quality/index.ts @@ -5,14 +5,10 @@ * 2.0. */ -import { TelemetryEventTypes } from '../../constants'; -import type { - DataQualityTelemetryCheckAllCompletedEvent, - DataQualityTelemetryIndexCheckedEvent, -} from '../../types'; +import { DataQualityEventTypes, type DataQualityTelemetryEvents } from './types'; -export const dataQualityIndexCheckedEvent: DataQualityTelemetryIndexCheckedEvent = { - eventType: TelemetryEventTypes.DataQualityIndexChecked, +export const dataQualityIndexCheckedEvent: DataQualityTelemetryEvents = { + eventType: DataQualityEventTypes.DataQualityIndexChecked, schema: { batchId: { type: 'keyword', @@ -163,8 +159,8 @@ export const dataQualityIndexCheckedEvent: DataQualityTelemetryIndexCheckedEvent }, }; -export const dataQualityCheckAllClickedEvent: DataQualityTelemetryCheckAllCompletedEvent = { - eventType: TelemetryEventTypes.DataQualityCheckAllCompleted, +export const dataQualityCheckAllClickedEvent: DataQualityTelemetryEvents = { + eventType: DataQualityEventTypes.DataQualityCheckAllCompleted, schema: { batchId: { type: 'keyword', @@ -259,3 +255,8 @@ export const dataQualityCheckAllClickedEvent: DataQualityTelemetryCheckAllComple }, }, }; + +export const dataQualityTelemetryEvents = [ + dataQualityIndexCheckedEvent, + dataQualityCheckAllClickedEvent, +]; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/data_quality/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/data_quality/types.ts index 9e1d012811e3..a6eca7eafc9c 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/data_quality/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/data_quality/types.ts @@ -6,7 +6,11 @@ */ import type { RootSchema } from '@kbn/core/public'; -import type { TelemetryEventTypes } from '../../constants'; + +export enum DataQualityEventTypes { + DataQualityIndexChecked = 'Data Quality Index Checked', + DataQualityCheckAllCompleted = 'Data Quality Check All Completed', +} export type ReportDataQualityIndexCheckedParams = ReportDataQualityCheckAllCompletedParams & { errorCount?: number; @@ -34,16 +38,12 @@ export interface ReportDataQualityCheckAllCompletedParams { timeConsumedMs?: number; } -export interface DataQualityTelemetryIndexCheckedEvent { - eventType: TelemetryEventTypes.DataQualityIndexChecked; - schema: RootSchema; +export interface DataQualityTelemetryEventsMap { + [DataQualityEventTypes.DataQualityIndexChecked]: ReportDataQualityIndexCheckedParams; + [DataQualityEventTypes.DataQualityCheckAllCompleted]: ReportDataQualityCheckAllCompletedParams; } -export interface DataQualityTelemetryCheckAllCompletedEvent { - eventType: TelemetryEventTypes.DataQualityCheckAllCompleted; - schema: RootSchema; +export interface DataQualityTelemetryEvents { + eventType: DataQualityEventTypes; + schema: RootSchema; } - -export type DataQualityTelemetryEvents = - | DataQualityTelemetryIndexCheckedEvent - | DataQualityTelemetryCheckAllCompletedEvent; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/document_details/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/document_details/index.ts index ba59cf5130dc..6cb27693464b 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/document_details/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/document_details/index.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { TelemetryEvent } from '../../types'; -import { TelemetryEventTypes } from '../../constants'; +import type { DocumentDetailsTelemetryEvent } from './types'; +import { DocumentEventTypes } from './types'; -export const DocumentDetailsFlyoutOpenedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.DetailsFlyoutOpened, +export const DocumentDetailsFlyoutOpenedEvent: DocumentDetailsTelemetryEvent = { + eventType: DocumentEventTypes.DetailsFlyoutOpened, schema: { location: { type: 'text', @@ -28,8 +28,8 @@ export const DocumentDetailsFlyoutOpenedEvent: TelemetryEvent = { }, }; -export const DocumentDetailsTabClickedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.DetailsFlyoutTabClicked, +export const DocumentDetailsTabClickedEvent: DocumentDetailsTelemetryEvent = { + eventType: DocumentEventTypes.DetailsFlyoutTabClicked, schema: { location: { type: 'text', @@ -54,3 +54,8 @@ export const DocumentDetailsTabClickedEvent: TelemetryEvent = { }, }, }; + +export const documentTelemetryEvents = [ + DocumentDetailsFlyoutOpenedEvent, + DocumentDetailsTabClickedEvent, +]; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/document_details/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/document_details/types.ts index 7a3ff374eae3..603b169e7740 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/document_details/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/document_details/types.ts @@ -6,29 +6,29 @@ */ import type { RootSchema } from '@kbn/core/public'; -import type { TelemetryEventTypes } from '../../constants'; -export interface ReportDetailsFlyoutOpenedParams { +export enum DocumentEventTypes { + DetailsFlyoutOpened = 'Details Flyout Opened', + DetailsFlyoutTabClicked = 'Details Flyout Tabs Clicked', +} + +interface ReportDetailsFlyoutOpenedParams { location: string; panel: 'left' | 'right' | 'preview'; } -export interface ReportDetailsFlyoutTabClickedParams { +interface ReportDetailsFlyoutTabClickedParams { location: string; panel: 'left' | 'right'; tabId: string; } -export type ReportDocumentDetailsTelemetryEventParams = - | ReportDetailsFlyoutOpenedParams - | ReportDetailsFlyoutTabClickedParams; +export interface DocumentDetailsTelemetryEventsMap { + [DocumentEventTypes.DetailsFlyoutOpened]: ReportDetailsFlyoutOpenedParams; + [DocumentEventTypes.DetailsFlyoutTabClicked]: ReportDetailsFlyoutTabClickedParams; +} -export type DocumentDetailsTelemetryEvents = - | { - eventType: TelemetryEventTypes.DetailsFlyoutOpened; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.DetailsFlyoutTabClicked; - schema: RootSchema; - }; +export interface DocumentDetailsTelemetryEvent { + eventType: DocumentEventTypes; + schema: RootSchema; +} diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/index.ts index 5a45970de6af..771957d7a882 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/index.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { TelemetryEvent } from '../../types'; -import { TelemetryEventTypes } from '../../constants'; +import type { EntityAnalyticsTelemetryEvent } from './types'; +import { EntityEventTypes } from './types'; -export const entityClickedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.EntityDetailsClicked, +export const entityClickedEvent: EntityAnalyticsTelemetryEvent = { + eventType: EntityEventTypes.EntityDetailsClicked, schema: { entity: { type: 'keyword', @@ -21,8 +21,8 @@ export const entityClickedEvent: TelemetryEvent = { }, }; -export const entityAlertsClickedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.EntityAlertsClicked, +export const entityAlertsClickedEvent: EntityAnalyticsTelemetryEvent = { + eventType: EntityEventTypes.EntityAlertsClicked, schema: { entity: { type: 'keyword', @@ -34,8 +34,8 @@ export const entityAlertsClickedEvent: TelemetryEvent = { }, }; -export const entityRiskFilteredEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.EntityRiskFiltered, +export const entityRiskFilteredEvent: EntityAnalyticsTelemetryEvent = { + eventType: EntityEventTypes.EntityRiskFiltered, schema: { entity: { type: 'keyword', @@ -54,8 +54,8 @@ export const entityRiskFilteredEvent: TelemetryEvent = { }, }; -export const toggleRiskSummaryClickedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.ToggleRiskSummaryClicked, +export const toggleRiskSummaryClickedEvent: EntityAnalyticsTelemetryEvent = { + eventType: EntityEventTypes.ToggleRiskSummaryClicked, schema: { entity: { type: 'keyword', @@ -74,8 +74,8 @@ export const toggleRiskSummaryClickedEvent: TelemetryEvent = { }, }; -export const RiskInputsExpandedFlyoutOpenedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.RiskInputsExpandedFlyoutOpened, +export const RiskInputsExpandedFlyoutOpenedEvent: EntityAnalyticsTelemetryEvent = { + eventType: EntityEventTypes.RiskInputsExpandedFlyoutOpened, schema: { entity: { type: 'keyword', @@ -87,8 +87,8 @@ export const RiskInputsExpandedFlyoutOpenedEvent: TelemetryEvent = { }, }; -export const addRiskInputToTimelineClickedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.AddRiskInputToTimelineClicked, +export const addRiskInputToTimelineClickedEvent: EntityAnalyticsTelemetryEvent = { + eventType: EntityEventTypes.AddRiskInputToTimelineClicked, schema: { quantity: { type: 'integer', @@ -100,8 +100,8 @@ export const addRiskInputToTimelineClickedEvent: TelemetryEvent = { }, }; -export const assetCriticalityFileSelectedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.AssetCriticalityFileSelected, +export const assetCriticalityFileSelectedEvent: EntityAnalyticsTelemetryEvent = { + eventType: EntityEventTypes.AssetCriticalityFileSelected, schema: { valid: { type: 'boolean', @@ -131,8 +131,8 @@ export const assetCriticalityFileSelectedEvent: TelemetryEvent = { }, }; -export const assetCriticalityCsvPreviewGeneratedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.AssetCriticalityCsvPreviewGenerated, +export const assetCriticalityCsvPreviewGeneratedEvent: EntityAnalyticsTelemetryEvent = { + eventType: EntityEventTypes.AssetCriticalityCsvPreviewGenerated, schema: { file: { properties: { @@ -198,8 +198,8 @@ export const assetCriticalityCsvPreviewGeneratedEvent: TelemetryEvent = { }, }; -export const assetCriticalityCsvImportedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.AssetCriticalityCsvImported, +export const assetCriticalityCsvImportedEvent: EntityAnalyticsTelemetryEvent = { + eventType: EntityEventTypes.AssetCriticalityCsvImported, schema: { file: { properties: { @@ -215,8 +215,8 @@ export const assetCriticalityCsvImportedEvent: TelemetryEvent = { }, }; -export const entityStoreInitEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.EntityStoreDashboardInitButtonClicked, +export const entityStoreInitEvent: EntityAnalyticsTelemetryEvent = { + eventType: EntityEventTypes.EntityStoreDashboardInitButtonClicked, schema: { timestamp: { type: 'date', @@ -228,8 +228,8 @@ export const entityStoreInitEvent: TelemetryEvent = { }, }; -export const entityStoreEnablementEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.EntityStoreEnablementToggleClicked, +export const entityStoreEnablementEvent: EntityAnalyticsTelemetryEvent = { + eventType: EntityEventTypes.EntityStoreEnablementToggleClicked, schema: { timestamp: { type: 'date', @@ -247,3 +247,80 @@ export const entityStoreEnablementEvent: TelemetryEvent = { }, }, }; + +const mlJobUpdateEvent: EntityAnalyticsTelemetryEvent = { + eventType: EntityEventTypes.MLJobUpdate, + schema: { + jobId: { + type: 'keyword', + _meta: { + description: 'Job id', + optional: false, + }, + }, + isElasticJob: { + type: 'boolean', + _meta: { + description: 'If true the job is one of the pre-configure security solution modules', + optional: false, + }, + }, + moduleId: { + type: 'keyword', + _meta: { + description: 'Module id', + optional: true, + }, + }, + status: { + type: 'keyword', + _meta: { + description: 'It describes what has changed in the job.', + optional: false, + }, + }, + errorMessage: { + type: 'text', + _meta: { + description: 'Error message', + optional: true, + }, + }, + }, +}; + +const anomaliesCountClickedEvent: EntityAnalyticsTelemetryEvent = { + eventType: EntityEventTypes.AnomaliesCountClicked, + schema: { + jobId: { + type: 'keyword', + _meta: { + description: 'Job id', + optional: false, + }, + }, + count: { + type: 'integer', + _meta: { + description: 'Number of anomalies', + optional: false, + }, + }, + }, +}; + +export const entityTelemetryEvents = [ + entityClickedEvent, + entityAlertsClickedEvent, + entityRiskFilteredEvent, + assetCriticalityCsvPreviewGeneratedEvent, + assetCriticalityFileSelectedEvent, + assetCriticalityCsvImportedEvent, + entityStoreEnablementEvent, + entityStoreInitEvent, + toggleRiskSummaryClickedEvent, + RiskInputsExpandedFlyoutOpenedEvent, + addRiskInputToTimelineClickedEvent, + mlJobUpdateEvent, + anomaliesCountClickedEvent, +]; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/types.ts index 3313e99a3118..3051d675b6b1 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/entity_analytics/types.ts @@ -7,29 +7,52 @@ import type { RootSchema } from '@kbn/core/public'; import type { RiskSeverity } from '../../../../../../common/search_strategy'; -import type { TelemetryEventTypes } from '../../constants'; +export enum EntityEventTypes { + EntityDetailsClicked = 'Entity Details Clicked', + EntityAlertsClicked = 'Entity Alerts Clicked', + EntityRiskFiltered = 'Entity Risk Filtered', + EntityStoreEnablementToggleClicked = 'Entity Store Enablement Toggle Clicked', + EntityStoreDashboardInitButtonClicked = 'Entity Store Initialization Button Clicked', + ToggleRiskSummaryClicked = 'Toggle Risk Summary Clicked', + AddRiskInputToTimelineClicked = 'Add Risk Input To Timeline Clicked', + RiskInputsExpandedFlyoutOpened = 'Risk Inputs Expanded Flyout Opened', + AssetCriticalityCsvPreviewGenerated = 'Asset Criticality Csv Preview Generated', + AssetCriticalityFileSelected = 'Asset Criticality File Selected', + AssetCriticalityCsvImported = 'Asset Criticality CSV Imported', + AnomaliesCountClicked = 'Anomalies Count Clicked', + MLJobUpdate = 'ML Job Update', +} + +export enum ML_JOB_TELEMETRY_STATUS { + started = 'started', + startError = 'start_error', + stopped = 'stopped', + stopError = 'stop_error', + moduleInstalled = 'module_installed', + installationError = 'installationError', +} interface EntityParam { entity: 'host' | 'user'; } -export type ReportEntityDetailsClickedParams = EntityParam; -export type ReportEntityAlertsClickedParams = EntityParam; -export interface ReportEntityRiskFilteredParams extends Partial { +type ReportEntityDetailsClickedParams = EntityParam; +type ReportEntityAlertsClickedParams = EntityParam; +interface ReportEntityRiskFilteredParams extends Partial { selectedSeverity: RiskSeverity; } -export interface ReportToggleRiskSummaryClickedParams extends EntityParam { +interface ReportToggleRiskSummaryClickedParams extends EntityParam { action: 'show' | 'hide'; } -export type ReportRiskInputsExpandedFlyoutOpenedParams = EntityParam; +type ReportRiskInputsExpandedFlyoutOpenedParams = EntityParam; -export interface ReportAddRiskInputToTimelineClickedParams { +interface ReportAddRiskInputToTimelineClickedParams { quantity: number; } -export interface ReportAssetCriticalityFileSelectedParams { +interface ReportAssetCriticalityFileSelectedParams { valid: boolean; errorCode?: string; file: { @@ -37,7 +60,7 @@ export interface ReportAssetCriticalityFileSelectedParams { }; } -export interface ReportAssetCriticalityCsvPreviewGeneratedParams { +interface ReportAssetCriticalityCsvPreviewGeneratedParams { file: { size: number; }; @@ -53,76 +76,51 @@ export interface ReportAssetCriticalityCsvPreviewGeneratedParams { }; } -export interface ReportAssetCriticalityCsvImportedParams { +interface ReportAssetCriticalityCsvImportedParams { file: { size: number; }; } -export interface ReportEntityStoreEnablementParams { +interface ReportAnomaliesCountClickedParams { + jobId: string; + count: number; +} + +interface ReportEntityStoreEnablementParams { timestamp: string; action: 'start' | 'stop'; } -export interface ReportEntityStoreInitParams { +interface ReportEntityStoreInitParams { timestamp: string; } -export type ReportEntityAnalyticsTelemetryEventParams = - | ReportEntityDetailsClickedParams - | ReportEntityAlertsClickedParams - | ReportEntityRiskFilteredParams - | ReportToggleRiskSummaryClickedParams - | ReportRiskInputsExpandedFlyoutOpenedParams - | ReportAddRiskInputToTimelineClickedParams - | ReportAssetCriticalityCsvPreviewGeneratedParams - | ReportAssetCriticalityFileSelectedParams - | ReportAssetCriticalityCsvImportedParams - | ReportEntityStoreEnablementParams - | ReportEntityStoreInitParams; - -export type EntityAnalyticsTelemetryEvent = - | { - eventType: TelemetryEventTypes.EntityDetailsClicked; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.EntityAlertsClicked; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.EntityRiskFiltered; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.AddRiskInputToTimelineClicked; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.ToggleRiskSummaryClicked; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.RiskInputsExpandedFlyoutOpened; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.AssetCriticalityCsvPreviewGenerated; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.AssetCriticalityFileSelected; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.AssetCriticalityCsvImported; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.EntityStoreEnablementToggleClicked; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.EntityStoreDashboardInitButtonClicked; - schema: RootSchema; - }; +interface ReportMLJobUpdateParams { + jobId: string; + isElasticJob: boolean; + status: ML_JOB_TELEMETRY_STATUS; + moduleId?: string; + errorMessage?: string; +} + +export interface EntityAnalyticsTelemetryEventsMap { + [EntityEventTypes.EntityDetailsClicked]: ReportEntityDetailsClickedParams; + [EntityEventTypes.EntityAlertsClicked]: ReportEntityAlertsClickedParams; + [EntityEventTypes.EntityRiskFiltered]: ReportEntityRiskFilteredParams; + [EntityEventTypes.EntityStoreEnablementToggleClicked]: ReportEntityStoreEnablementParams; + [EntityEventTypes.EntityStoreDashboardInitButtonClicked]: ReportEntityStoreInitParams; + [EntityEventTypes.ToggleRiskSummaryClicked]: ReportToggleRiskSummaryClickedParams; + [EntityEventTypes.AddRiskInputToTimelineClicked]: ReportAddRiskInputToTimelineClickedParams; + [EntityEventTypes.RiskInputsExpandedFlyoutOpened]: ReportRiskInputsExpandedFlyoutOpenedParams; + [EntityEventTypes.AssetCriticalityCsvPreviewGenerated]: ReportAssetCriticalityCsvPreviewGeneratedParams; + [EntityEventTypes.AssetCriticalityFileSelected]: ReportAssetCriticalityFileSelectedParams; + [EntityEventTypes.AssetCriticalityCsvImported]: ReportAssetCriticalityCsvImportedParams; + [EntityEventTypes.AnomaliesCountClicked]: ReportAnomaliesCountClickedParams; + [EntityEventTypes.MLJobUpdate]: ReportMLJobUpdateParams; +} + +export interface EntityAnalyticsTelemetryEvent { + eventType: EntityEventTypes; + schema: RootSchema; +} diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/event_log/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/event_log/index.ts index c30efcee10cf..7e34afa0aec6 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/event_log/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/event_log/index.ts @@ -6,10 +6,10 @@ */ import type { EventLogTelemetryEvent } from './types'; -import { TelemetryEventTypes } from '../../constants'; +import { EventLogEventTypes } from './types'; export const eventLogFilterByRunTypeEvent: EventLogTelemetryEvent = { - eventType: TelemetryEventTypes.EventLogFilterByRunType, + eventType: EventLogEventTypes.EventLogFilterByRunType, schema: { runType: { type: 'array', @@ -24,7 +24,7 @@ export const eventLogFilterByRunTypeEvent: EventLogTelemetryEvent = { }; export const eventLogShowSourceEventDateRangeEvent: EventLogTelemetryEvent = { - eventType: TelemetryEventTypes.EventLogShowSourceEventDateRange, + eventType: EventLogEventTypes.EventLogShowSourceEventDateRange, schema: { isVisible: { type: 'boolean', @@ -35,3 +35,8 @@ export const eventLogShowSourceEventDateRangeEvent: EventLogTelemetryEvent = { }, }, }; + +export const eventLogTelemetryEvents = [ + eventLogFilterByRunTypeEvent, + eventLogShowSourceEventDateRangeEvent, +]; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/event_log/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/event_log/types.ts index b196c9010b25..a2a32290ce40 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/event_log/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/event_log/types.ts @@ -5,25 +5,24 @@ * 2.0. */ import type { RootSchema } from '@kbn/core/public'; -import type { TelemetryEventTypes } from '../../constants'; -export interface ReportEventLogFilterByRunTypeParams { +export enum EventLogEventTypes { + EventLogFilterByRunType = 'Event Log Filter By Run Type', + EventLogShowSourceEventDateRange = 'Event Log -> Show Source -> Event Date Range', +} +interface ReportEventLogFilterByRunTypeParams { runType: string[]; } -export interface ReportEventLogShowSourceEventDateRangeParams { +interface ReportEventLogShowSourceEventDateRangeParams { isVisible: boolean; } -export type ReportEventLogTelemetryEventParams = - | ReportEventLogFilterByRunTypeParams - | ReportEventLogShowSourceEventDateRangeParams; +export interface EventLogTelemetryEventsMap { + [EventLogEventTypes.EventLogFilterByRunType]: ReportEventLogFilterByRunTypeParams; + [EventLogEventTypes.EventLogShowSourceEventDateRange]: ReportEventLogShowSourceEventDateRangeParams; +} -export type EventLogTelemetryEvent = - | { - eventType: TelemetryEventTypes.EventLogFilterByRunType; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.EventLogShowSourceEventDateRange; - schema: RootSchema; - }; +export interface EventLogTelemetryEvent { + eventType: EventLogEventTypes; + schema: RootSchema; +} diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/manual_rule_run/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/manual_rule_run/index.ts index a1476944d980..3bc616dca1cf 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/manual_rule_run/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/manual_rule_run/index.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { TelemetryEvent } from '../../types'; -import { TelemetryEventTypes } from '../../constants'; +import type { ManualRuleRunTelemetryEvent } from './types'; +import { ManualRuleRunEventTypes } from './types'; -export const manualRuleRunOpenModalEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.ManualRuleRunOpenModal, +export const manualRuleRunOpenModalEvent: ManualRuleRunTelemetryEvent = { + eventType: ManualRuleRunEventTypes.ManualRuleRunOpenModal, schema: { type: { type: 'keyword', @@ -21,8 +21,8 @@ export const manualRuleRunOpenModalEvent: TelemetryEvent = { }, }; -export const manualRuleRunExecuteEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.ManualRuleRunExecute, +export const manualRuleRunExecuteEvent: ManualRuleRunTelemetryEvent = { + eventType: ManualRuleRunEventTypes.ManualRuleRunExecute, schema: { rangeInMs: { type: 'integer', @@ -50,8 +50,8 @@ export const manualRuleRunExecuteEvent: TelemetryEvent = { }, }; -export const manualRuleRunCancelJobEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.ManualRuleRunCancelJob, +export const manualRuleRunCancelJobEvent: ManualRuleRunTelemetryEvent = { + eventType: ManualRuleRunEventTypes.ManualRuleRunCancelJob, schema: { totalTasks: { type: 'integer', @@ -77,3 +77,9 @@ export const manualRuleRunCancelJobEvent: TelemetryEvent = { }, }, }; + +export const manualRuleRunTelemetryEvents = [ + manualRuleRunCancelJobEvent, + manualRuleRunExecuteEvent, + manualRuleRunOpenModalEvent, +]; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/manual_rule_run/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/manual_rule_run/types.ts index a58b0adf4550..231b555408e5 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/manual_rule_run/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/manual_rule_run/types.ts @@ -5,39 +5,35 @@ * 2.0. */ import type { RootSchema } from '@kbn/core/public'; -import type { TelemetryEventTypes } from '../../constants'; -export interface ReportManualRuleRunOpenModalParams { +export enum ManualRuleRunEventTypes { + ManualRuleRunOpenModal = 'Manual Rule Run Open Modal', + ManualRuleRunExecute = 'Manual Rule Run Execute', + ManualRuleRunCancelJob = 'Manual Rule Run Cancel Job', +} +interface ReportManualRuleRunOpenModalParams { type: 'single' | 'bulk'; } -export interface ReportManualRuleRunExecuteParams { +interface ReportManualRuleRunExecuteParams { rangeInMs: number; rulesCount: number; status: 'success' | 'error'; } -export interface ReportManualRuleRunCancelJobParams { +interface ReportManualRuleRunCancelJobParams { totalTasks: number; completedTasks: number; errorTasks: number; } -export type ReportManualRuleRunTelemetryEventParams = - | ReportManualRuleRunOpenModalParams - | ReportManualRuleRunExecuteParams - | ReportManualRuleRunCancelJobParams; +export interface ManualRuleRunTelemetryEventsMap { + [ManualRuleRunEventTypes.ManualRuleRunOpenModal]: ReportManualRuleRunOpenModalParams; + [ManualRuleRunEventTypes.ManualRuleRunExecute]: ReportManualRuleRunExecuteParams; + [ManualRuleRunEventTypes.ManualRuleRunCancelJob]: ReportManualRuleRunCancelJobParams; +} -export type ManualRuleRunTelemetryEvent = - | { - eventType: TelemetryEventTypes.ManualRuleRunOpenModal; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.ManualRuleRunExecute; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.ManualRuleRunCancelJob; - schema: RootSchema; - }; +export interface ManualRuleRunTelemetryEvent { + eventType: ManualRuleRunEventTypes; + schema: RootSchema; +} diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/notes/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/notes/index.ts index c560f69730d3..94c9c350e010 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/notes/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/notes/index.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { TelemetryEvent } from '../../types'; -import { TelemetryEventTypes } from '../../constants'; +import type { NotesTelemetryEvent } from './types'; +import { NotesEventTypes } from './types'; -export const openNoteInExpandableFlyoutClickedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.OpenNoteInExpandableFlyoutClicked, +export const openNoteInExpandableFlyoutClickedEvent: NotesTelemetryEvent = { + eventType: NotesEventTypes.OpenNoteInExpandableFlyoutClicked, schema: { location: { type: 'text', @@ -21,8 +21,8 @@ export const openNoteInExpandableFlyoutClickedEvent: TelemetryEvent = { }, }; -export const addNoteFromExpandableFlyoutClickedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.AddNoteFromExpandableFlyoutClicked, +export const addNoteFromExpandableFlyoutClickedEvent: NotesTelemetryEvent = { + eventType: NotesEventTypes.AddNoteFromExpandableFlyoutClicked, schema: { isRelatedToATimeline: { type: 'boolean', @@ -33,3 +33,8 @@ export const addNoteFromExpandableFlyoutClickedEvent: TelemetryEvent = { }, }, }; + +export const notesTelemetryEvents = [ + openNoteInExpandableFlyoutClickedEvent, + addNoteFromExpandableFlyoutClickedEvent, +]; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/notes/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/notes/types.ts index a785f2f8493e..76440215c807 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/notes/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/notes/types.ts @@ -6,26 +6,26 @@ */ import type { RootSchema } from '@kbn/core/public'; -import type { TelemetryEventTypes } from '../../constants'; -export interface OpenNoteInExpandableFlyoutClickedParams { +interface OpenNoteInExpandableFlyoutClickedParams { location: string; } -export interface AddNoteFromExpandableFlyoutClickedParams { +interface AddNoteFromExpandableFlyoutClickedParams { isRelatedToATimeline: boolean; } -export type NotesTelemetryEventParams = - | OpenNoteInExpandableFlyoutClickedParams - | AddNoteFromExpandableFlyoutClickedParams; +export enum NotesEventTypes { + OpenNoteInExpandableFlyoutClicked = 'Open Note In Expandable Flyout Clicked', + AddNoteFromExpandableFlyoutClicked = 'Add Note From Expandable Flyout Clicked', +} + +export interface NotesTelemetryEventsMap { + [NotesEventTypes.OpenNoteInExpandableFlyoutClicked]: OpenNoteInExpandableFlyoutClickedParams; + [NotesEventTypes.AddNoteFromExpandableFlyoutClicked]: AddNoteFromExpandableFlyoutClickedParams; +} -export type NotesTelemetryEvents = - | { - eventType: TelemetryEventTypes.OpenNoteInExpandableFlyoutClicked; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.AddNoteFromExpandableFlyoutClicked; - schema: RootSchema; - }; +export interface NotesTelemetryEvent { + eventType: NotesEventTypes; + schema: RootSchema; +} diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/onboarding/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/onboarding/index.ts index dacb0c948328..75a35e2d61c5 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/onboarding/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/onboarding/index.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { TelemetryEvent } from '../../types'; -import { TelemetryEventTypes } from '../../constants'; +import type { OnboardingHubTelemetryEvent } from './types'; +import { OnboardingHubEventTypes } from './types'; -export const onboardingHubStepOpenEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.OnboardingHubStepOpen, +export const onboardingHubStepOpenEvent: OnboardingHubTelemetryEvent = { + eventType: OnboardingHubEventTypes.OnboardingHubStepOpen, schema: { stepId: { type: 'keyword', @@ -28,8 +28,8 @@ export const onboardingHubStepOpenEvent: TelemetryEvent = { }, }; -export const onboardingHubStepLinkClickedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.OnboardingHubStepLinkClicked, +export const onboardingHubStepLinkClickedEvent: OnboardingHubTelemetryEvent = { + eventType: OnboardingHubEventTypes.OnboardingHubStepLinkClicked, schema: { originStepId: { type: 'keyword', @@ -48,8 +48,8 @@ export const onboardingHubStepLinkClickedEvent: TelemetryEvent = { }, }; -export const onboardingHubStepFinishedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.OnboardingHubStepFinished, +export const onboardingHubStepFinishedEvent: OnboardingHubTelemetryEvent = { + eventType: OnboardingHubEventTypes.OnboardingHubStepFinished, schema: { stepId: { type: 'keyword', @@ -74,3 +74,9 @@ export const onboardingHubStepFinishedEvent: TelemetryEvent = { }, }, }; + +export const onboardingHubTelemetryEvents = [ + onboardingHubStepOpenEvent, + onboardingHubStepLinkClickedEvent, + onboardingHubStepFinishedEvent, +]; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/onboarding/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/onboarding/types.ts index 224635715b32..d11e9800e16f 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/onboarding/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/onboarding/types.ts @@ -5,30 +5,25 @@ * 2.0. */ import type { RootSchema } from '@kbn/core/public'; -import type { TelemetryEventTypes } from '../../constants'; -export type OnboardingHubStepOpenTrigger = 'navigation' | 'click'; +export enum OnboardingHubEventTypes { + OnboardingHubStepOpen = 'Onboarding Hub Step Open', + OnboardingHubStepFinished = 'Onboarding Hub Step Finished', + OnboardingHubStepLinkClicked = 'Onboarding Hub Step Link Clicked', +} + +type OnboardingHubStepOpenTrigger = 'navigation' | 'click'; -export interface OnboardingHubStepOpenParams { +interface OnboardingHubStepOpenParams { stepId: string; trigger: OnboardingHubStepOpenTrigger; } -export interface OnboardingHubStepOpen { - eventType: TelemetryEventTypes.OnboardingHubStepOpen; - schema: RootSchema; -} - export interface OnboardingHubStepLinkClickedParams { originStepId: string; stepLinkId: string; } -export interface OnboardingHubStepLinkClicked { - eventType: TelemetryEventTypes.OnboardingHubStepLinkClicked; - schema: RootSchema; -} - export type OnboardingHubStepFinishedTrigger = 'auto_check' | 'click'; export interface OnboardingHubStepFinishedParams { @@ -37,12 +32,13 @@ export interface OnboardingHubStepFinishedParams { trigger: OnboardingHubStepFinishedTrigger; } -export interface OnboardingHubStepFinished { - eventType: TelemetryEventTypes.OnboardingHubStepFinished; - schema: RootSchema; +export interface OnboardingHubTelemetryEventsMap { + [OnboardingHubEventTypes.OnboardingHubStepOpen]: OnboardingHubStepOpenParams; + [OnboardingHubEventTypes.OnboardingHubStepFinished]: OnboardingHubStepFinishedParams; + [OnboardingHubEventTypes.OnboardingHubStepLinkClicked]: OnboardingHubStepLinkClickedParams; } -export type OnboardingHubTelemetryEvent = - | OnboardingHubStepOpen - | OnboardingHubStepFinished - | OnboardingHubStepLinkClicked; +export interface OnboardingHubTelemetryEvent { + eventType: OnboardingHubEventTypes; + schema: RootSchema; +} diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/index.ts index 12d721c45e2c..f34380935b0e 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/index.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { TelemetryEvent } from '../../types'; -import { TelemetryEventTypes } from '../../constants'; +import type { PreviewRuleTelemetryEvent } from './types'; +import { PreviewRuleEventTypes } from './types'; -export const previewRuleEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.PreviewRule, +export const previewRuleEvent: PreviewRuleTelemetryEvent = { + eventType: PreviewRuleEventTypes.PreviewRule, schema: { ruleType: { type: 'keyword', @@ -27,3 +27,5 @@ export const previewRuleEvent: TelemetryEvent = { }, }, }; + +export const previewRuleTelemetryEvents = [previewRuleEvent]; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/types.ts index e5523080088f..876378e24553 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/preview_rule/types.ts @@ -7,14 +7,21 @@ import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import type { RootSchema } from '@kbn/core/public'; -import type { TelemetryEventTypes } from '../../constants'; -export interface PreviewRuleParams { +interface PreviewRuleParams { ruleType: Type; loggedRequestsEnabled: boolean; } +export enum PreviewRuleEventTypes { + PreviewRule = 'Preview rule', +} + +export interface PreviewRuleTelemetryEventsMap { + [PreviewRuleEventTypes.PreviewRule]: PreviewRuleParams; +} + export interface PreviewRuleTelemetryEvent { - eventType: TelemetryEventTypes.PreviewRule; - schema: RootSchema; + eventType: PreviewRuleEventTypes; + schema: RootSchema; } diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/telemetry_events.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/telemetry_events.ts index 3e7c9f113839..b610f6e77dda 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/events/telemetry_events.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/events/telemetry_events.ts @@ -4,198 +4,28 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { TelemetryEvent } from '../types'; -import { TelemetryEventTypes } from '../constants'; -import { - alertsGroupingChangedEvent, - alertsGroupingTakeActionEvent, - alertsGroupingToggledEvent, -} from './alerts_grouping'; -import { - entityAlertsClickedEvent, - entityClickedEvent, - entityRiskFilteredEvent, - addRiskInputToTimelineClickedEvent, - RiskInputsExpandedFlyoutOpenedEvent, - toggleRiskSummaryClickedEvent, - assetCriticalityCsvPreviewGeneratedEvent, - assetCriticalityFileSelectedEvent, - assetCriticalityCsvImportedEvent, - entityStoreEnablementEvent, - entityStoreInitEvent, -} from './entity_analytics'; -import { - assistantInvokedEvent, - assistantSettingToggledEvent, - assistantMessageSentEvent, - assistantQuickPrompt, -} from './ai_assistant'; -import { dataQualityIndexCheckedEvent, dataQualityCheckAllClickedEvent } from './data_quality'; -import { - DocumentDetailsFlyoutOpenedEvent, - DocumentDetailsTabClickedEvent, -} from './document_details'; -import { - onboardingHubStepFinishedEvent, - onboardingHubStepLinkClickedEvent, - onboardingHubStepOpenEvent, -} from './onboarding'; -import { - manualRuleRunCancelJobEvent, - manualRuleRunExecuteEvent, - manualRuleRunOpenModalEvent, -} from './manual_rule_run'; -import { eventLogFilterByRunTypeEvent, eventLogShowSourceEventDateRangeEvent } from './event_log'; -import { - addNoteFromExpandableFlyoutClickedEvent, - openNoteInExpandableFlyoutClickedEvent, -} from './notes'; -import { previewRuleEvent } from './preview_rule'; - -const mlJobUpdateEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.MLJobUpdate, - schema: { - jobId: { - type: 'keyword', - _meta: { - description: 'Job id', - optional: false, - }, - }, - isElasticJob: { - type: 'boolean', - _meta: { - description: 'If true the job is one of the pre-configure security solution modules', - optional: false, - }, - }, - moduleId: { - type: 'keyword', - _meta: { - description: 'Module id', - optional: true, - }, - }, - status: { - type: 'keyword', - _meta: { - description: 'It describes what has changed in the job.', - optional: false, - }, - }, - errorMessage: { - type: 'text', - _meta: { - description: 'Error message', - optional: true, - }, - }, - }, -}; - -const cellActionClickedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.CellActionClicked, - schema: { - fieldName: { - type: 'keyword', - _meta: { - description: 'Field Name', - optional: false, - }, - }, - actionId: { - type: 'keyword', - _meta: { - description: 'Action id', - optional: false, - }, - }, - displayName: { - type: 'keyword', - _meta: { - description: 'User friendly action name', - optional: false, - }, - }, - metadata: { - type: 'pass_through', - _meta: { - description: 'Action metadata', - optional: true, - }, - }, - }, -}; - -const anomaliesCountClickedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.AnomaliesCountClicked, - schema: { - jobId: { - type: 'keyword', - _meta: { - description: 'Job id', - optional: false, - }, - }, - count: { - type: 'integer', - _meta: { - description: 'Number of anomalies', - optional: false, - }, - }, - }, -}; - -const breadCrumbClickedEvent: TelemetryEvent = { - eventType: TelemetryEventTypes.BreadcrumbClicked, - schema: { - title: { - type: 'keyword', - _meta: { - description: 'Breadcrumb title', - optional: false, - }, - }, - }, -}; +import { assistantTelemetryEvents } from './ai_assistant'; +import { alertsTelemetryEvents } from './alerts_grouping'; +import { appTelemetryEvents } from './app'; +import { dataQualityTelemetryEvents } from './data_quality'; +import { documentTelemetryEvents } from './document_details'; +import { entityTelemetryEvents } from './entity_analytics'; +import { eventLogTelemetryEvents } from './event_log'; +import { manualRuleRunTelemetryEvents } from './manual_rule_run'; +import { notesTelemetryEvents } from './notes'; +import { onboardingHubTelemetryEvents } from './onboarding'; +import { previewRuleTelemetryEvents } from './preview_rule'; export const telemetryEvents = [ - alertsGroupingToggledEvent, - alertsGroupingChangedEvent, - alertsGroupingTakeActionEvent, - assistantInvokedEvent, - assistantMessageSentEvent, - assistantQuickPrompt, - assistantSettingToggledEvent, - entityClickedEvent, - entityAlertsClickedEvent, - entityRiskFilteredEvent, - assetCriticalityCsvPreviewGeneratedEvent, - assetCriticalityFileSelectedEvent, - assetCriticalityCsvImportedEvent, - entityStoreEnablementEvent, - entityStoreInitEvent, - toggleRiskSummaryClickedEvent, - RiskInputsExpandedFlyoutOpenedEvent, - addRiskInputToTimelineClickedEvent, - mlJobUpdateEvent, - cellActionClickedEvent, - anomaliesCountClickedEvent, - dataQualityIndexCheckedEvent, - dataQualityCheckAllClickedEvent, - breadCrumbClickedEvent, - DocumentDetailsFlyoutOpenedEvent, - DocumentDetailsTabClickedEvent, - onboardingHubStepOpenEvent, - onboardingHubStepLinkClickedEvent, - onboardingHubStepFinishedEvent, - manualRuleRunCancelJobEvent, - manualRuleRunExecuteEvent, - manualRuleRunOpenModalEvent, - eventLogFilterByRunTypeEvent, - eventLogShowSourceEventDateRangeEvent, - openNoteInExpandableFlyoutClickedEvent, - addNoteFromExpandableFlyoutClickedEvent, - previewRuleEvent, + ...assistantTelemetryEvents, + ...alertsTelemetryEvents, + ...previewRuleTelemetryEvents, + ...entityTelemetryEvents, + ...dataQualityTelemetryEvents, + ...documentTelemetryEvents, + ...onboardingHubTelemetryEvents, + ...manualRuleRunTelemetryEvents, + ...eventLogTelemetryEvents, + ...notesTelemetryEvents, + ...appTelemetryEvents, ]; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/index.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/index.ts index 5a6818c712de..a8df452d512a 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/index.ts @@ -5,23 +5,9 @@ * 2.0. */ -import type { AlertWorkflowStatus } from '../../types'; export { telemetryMiddleware } from './middleware'; export * from './constants'; -export * from './telemetry_client'; export * from './telemetry_service'; export * from './track'; export * from './types'; - -export const getTelemetryEvent = { - groupedAlertsTakeAction: ({ - tableId, - groupNumber, - status, - }: { - tableId: string; - groupNumber: number; - status: AlertWorkflowStatus; - }) => `alerts_table_${tableId}_group-${groupNumber}_mark-${status}`, -}; diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.mock.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.mock.ts deleted file mode 100644 index 87d4b215543d..000000000000 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.mock.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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { TelemetryClientStart } from './types'; - -export const createTelemetryClientMock = (): jest.Mocked => ({ - reportAlertsGroupingChanged: jest.fn(), - reportAlertsGroupingToggled: jest.fn(), - reportAlertsGroupingTakeAction: jest.fn(), - reportAssistantInvoked: jest.fn(), - reportAssistantMessageSent: jest.fn(), - reportAssistantQuickPrompt: jest.fn(), - reportAssistantSettingToggled: jest.fn(), - reportEntityDetailsClicked: jest.fn(), - reportEntityAlertsClicked: jest.fn(), - reportEntityRiskFiltered: jest.fn(), - reportMLJobUpdate: jest.fn(), - reportCellActionClicked: jest.fn(), - reportAnomaliesCountClicked: jest.fn(), - reportDataQualityIndexChecked: jest.fn(), - reportDataQualityCheckAllCompleted: jest.fn(), - reportBreadcrumbClicked: jest.fn(), - reportToggleRiskSummaryClicked: jest.fn(), - reportRiskInputsExpandedFlyoutOpened: jest.fn(), - reportAddRiskInputToTimelineClicked: jest.fn(), - reportDetailsFlyoutOpened: jest.fn(), - reportDetailsFlyoutTabClicked: jest.fn(), - reportOnboardingHubStepOpen: jest.fn(), - reportOnboardingHubStepLinkClicked: jest.fn(), - reportOnboardingHubStepFinished: jest.fn(), - reportAssetCriticalityCsvPreviewGenerated: jest.fn(), - reportAssetCriticalityFileSelected: jest.fn(), - reportAssetCriticalityCsvImported: jest.fn(), - reportEventLogFilterByRunType: jest.fn(), - reportEventLogShowSourceEventDateRange: jest.fn(), - reportManualRuleRunCancelJob: jest.fn(), - reportManualRuleRunExecute: jest.fn(), - reportManualRuleRunOpenModal: jest.fn(), - reportOpenNoteInExpandableFlyoutClicked: jest.fn(), - reportAddNoteFromExpandableFlyoutClicked: jest.fn(), - reportPreviewRule: jest.fn(), - reportEntityStoreEnablement: jest.fn(), - reportEntityStoreInit: jest.fn(), -}); diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts deleted file mode 100644 index 689209f284db..000000000000 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_client.ts +++ /dev/null @@ -1,229 +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 { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; -import type { - AddNoteFromExpandableFlyoutClickedParams, - OpenNoteInExpandableFlyoutClickedParams, -} from './events/notes/types'; -import type { - TelemetryClientStart, - ReportAlertsGroupingChangedParams, - ReportAlertsGroupingToggledParams, - ReportAlertsTakeActionParams, - ReportEntityDetailsClickedParams, - ReportEntityAlertsClickedParams, - ReportEntityRiskFilteredParams, - ReportMLJobUpdateParams, - ReportCellActionClickedParams, - ReportAnomaliesCountClickedParams, - ReportDataQualityIndexCheckedParams, - ReportDataQualityCheckAllCompletedParams, - ReportBreadcrumbClickedParams, - ReportAssistantInvokedParams, - ReportAssistantMessageSentParams, - ReportAssistantQuickPromptParams, - ReportAssistantSettingToggledParams, - ReportRiskInputsExpandedFlyoutOpenedParams, - ReportToggleRiskSummaryClickedParams, - ReportDetailsFlyoutOpenedParams, - ReportDetailsFlyoutTabClickedParams, - ReportAssetCriticalityCsvPreviewGeneratedParams, - ReportAssetCriticalityFileSelectedParams, - ReportAssetCriticalityCsvImportedParams, - ReportAddRiskInputToTimelineClickedParams, - OnboardingHubStepLinkClickedParams, - OnboardingHubStepOpenParams, - OnboardingHubStepFinishedParams, - ReportManualRuleRunCancelJobParams, - ReportManualRuleRunExecuteParams, - ReportManualRuleRunOpenModalParams, - ReportEventLogShowSourceEventDateRangeParams, - ReportEventLogFilterByRunTypeParams, - PreviewRuleParams, - ReportEntityStoreEnablementParams, - ReportEntityStoreInitParams, -} from './types'; -import { TelemetryEventTypes } from './constants'; - -/** - * Client which aggregate all the available telemetry tracking functions - * for the plugin - */ -export class TelemetryClient implements TelemetryClientStart { - constructor(private analytics: AnalyticsServiceSetup) {} - - public reportAlertsGroupingChanged = (params: ReportAlertsGroupingChangedParams) => { - this.analytics.reportEvent(TelemetryEventTypes.AlertsGroupingChanged, params); - }; - - public reportAlertsGroupingToggled = (params: ReportAlertsGroupingToggledParams) => { - this.analytics.reportEvent(TelemetryEventTypes.AlertsGroupingToggled, params); - }; - - public reportAlertsGroupingTakeAction = (params: ReportAlertsTakeActionParams) => { - this.analytics.reportEvent(TelemetryEventTypes.AlertsGroupingTakeAction, params); - }; - - public reportAssistantInvoked = (params: ReportAssistantInvokedParams) => { - this.analytics.reportEvent(TelemetryEventTypes.AssistantInvoked, params); - }; - - public reportAssistantMessageSent = (params: ReportAssistantMessageSentParams) => { - this.analytics.reportEvent(TelemetryEventTypes.AssistantMessageSent, params); - }; - - public reportAssistantQuickPrompt = (params: ReportAssistantQuickPromptParams) => { - this.analytics.reportEvent(TelemetryEventTypes.AssistantQuickPrompt, params); - }; - - public reportAssistantSettingToggled = (params: ReportAssistantSettingToggledParams) => { - this.analytics.reportEvent(TelemetryEventTypes.AssistantSettingToggled, params); - }; - - public reportEntityDetailsClicked = ({ entity }: ReportEntityDetailsClickedParams) => { - this.analytics.reportEvent(TelemetryEventTypes.EntityDetailsClicked, { - entity, - }); - }; - - public reportEntityAlertsClicked = ({ entity }: ReportEntityAlertsClickedParams) => { - this.analytics.reportEvent(TelemetryEventTypes.EntityAlertsClicked, { - entity, - }); - }; - - public reportEntityRiskFiltered = ({ - entity, - selectedSeverity, - }: ReportEntityRiskFilteredParams) => { - this.analytics.reportEvent(TelemetryEventTypes.EntityRiskFiltered, { - entity, - selectedSeverity, - }); - }; - - public reportAssetCriticalityCsvPreviewGenerated = ( - params: ReportAssetCriticalityCsvPreviewGeneratedParams - ) => { - this.analytics.reportEvent(TelemetryEventTypes.AssetCriticalityCsvPreviewGenerated, params); - }; - - public reportAssetCriticalityFileSelected = ( - params: ReportAssetCriticalityFileSelectedParams - ) => { - this.analytics.reportEvent(TelemetryEventTypes.AssetCriticalityFileSelected, params); - }; - - public reportAssetCriticalityCsvImported = (params: ReportAssetCriticalityCsvImportedParams) => { - this.analytics.reportEvent(TelemetryEventTypes.AssetCriticalityCsvImported, params); - }; - - public reportMLJobUpdate = (params: ReportMLJobUpdateParams) => { - this.analytics.reportEvent(TelemetryEventTypes.MLJobUpdate, params); - }; - - reportToggleRiskSummaryClicked(params: ReportToggleRiskSummaryClickedParams): void { - this.analytics.reportEvent(TelemetryEventTypes.ToggleRiskSummaryClicked, params); - } - reportRiskInputsExpandedFlyoutOpened(params: ReportRiskInputsExpandedFlyoutOpenedParams): void { - this.analytics.reportEvent(TelemetryEventTypes.RiskInputsExpandedFlyoutOpened, params); - } - reportAddRiskInputToTimelineClicked(params: ReportAddRiskInputToTimelineClickedParams): void { - this.analytics.reportEvent(TelemetryEventTypes.AddRiskInputToTimelineClicked, params); - } - - public reportCellActionClicked = (params: ReportCellActionClickedParams) => { - this.analytics.reportEvent(TelemetryEventTypes.CellActionClicked, params); - }; - - public reportAnomaliesCountClicked = (params: ReportAnomaliesCountClickedParams) => { - this.analytics.reportEvent(TelemetryEventTypes.AnomaliesCountClicked, params); - }; - - public reportDataQualityIndexChecked = (params: ReportDataQualityIndexCheckedParams) => { - this.analytics.reportEvent(TelemetryEventTypes.DataQualityIndexChecked, params); - }; - - public reportDataQualityCheckAllCompleted = ( - params: ReportDataQualityCheckAllCompletedParams - ) => { - this.analytics.reportEvent(TelemetryEventTypes.DataQualityCheckAllCompleted, params); - }; - - public reportBreadcrumbClicked = ({ title }: ReportBreadcrumbClickedParams) => { - this.analytics.reportEvent(TelemetryEventTypes.BreadcrumbClicked, { - title, - }); - }; - - public reportDetailsFlyoutOpened = (params: ReportDetailsFlyoutOpenedParams) => { - this.analytics.reportEvent(TelemetryEventTypes.DetailsFlyoutOpened, params); - }; - - public reportDetailsFlyoutTabClicked = (params: ReportDetailsFlyoutTabClickedParams) => { - this.analytics.reportEvent(TelemetryEventTypes.DetailsFlyoutTabClicked, params); - }; - - public reportOnboardingHubStepOpen = (params: OnboardingHubStepOpenParams) => { - this.analytics.reportEvent(TelemetryEventTypes.OnboardingHubStepOpen, params); - }; - - public reportOnboardingHubStepFinished = (params: OnboardingHubStepFinishedParams) => { - this.analytics.reportEvent(TelemetryEventTypes.OnboardingHubStepFinished, params); - }; - - public reportOnboardingHubStepLinkClicked = (params: OnboardingHubStepLinkClickedParams) => { - this.analytics.reportEvent(TelemetryEventTypes.OnboardingHubStepLinkClicked, params); - }; - - public reportManualRuleRunOpenModal = (params: ReportManualRuleRunOpenModalParams) => { - this.analytics.reportEvent(TelemetryEventTypes.ManualRuleRunOpenModal, params); - }; - - public reportManualRuleRunExecute = (params: ReportManualRuleRunExecuteParams) => { - this.analytics.reportEvent(TelemetryEventTypes.ManualRuleRunExecute, params); - }; - - public reportManualRuleRunCancelJob = (params: ReportManualRuleRunCancelJobParams) => { - this.analytics.reportEvent(TelemetryEventTypes.ManualRuleRunCancelJob, params); - }; - - public reportEventLogFilterByRunType = (params: ReportEventLogFilterByRunTypeParams) => { - this.analytics.reportEvent(TelemetryEventTypes.EventLogFilterByRunType, params); - }; - - public reportEventLogShowSourceEventDateRange( - params: ReportEventLogShowSourceEventDateRangeParams - ): void { - this.analytics.reportEvent(TelemetryEventTypes.EventLogShowSourceEventDateRange, params); - } - - public reportOpenNoteInExpandableFlyoutClicked = ( - params: OpenNoteInExpandableFlyoutClickedParams - ) => { - this.analytics.reportEvent(TelemetryEventTypes.OpenNoteInExpandableFlyoutClicked, params); - }; - - public reportAddNoteFromExpandableFlyoutClicked = ( - params: AddNoteFromExpandableFlyoutClickedParams - ) => { - this.analytics.reportEvent(TelemetryEventTypes.AddNoteFromExpandableFlyoutClicked, params); - }; - - public reportPreviewRule = (params: PreviewRuleParams) => { - this.analytics.reportEvent(TelemetryEventTypes.PreviewRule, params); - }; - - public reportEntityStoreEnablement = (params: ReportEntityStoreEnablementParams) => { - this.analytics.reportEvent(TelemetryEventTypes.EntityStoreEnablementToggleClicked, params); - }; - - public reportEntityStoreInit = (params: ReportEntityStoreInitParams) => { - this.analytics.reportEvent(TelemetryEventTypes.EntityStoreDashboardInitButtonClicked, params); - }; -} diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.mock.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.mock.ts index 519ba4527560..30b8a0c434c5 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.mock.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.mock.ts @@ -5,6 +5,4 @@ * 2.0. */ -import { createTelemetryClientMock } from './telemetry_client.mock'; - -export const createTelemetryServiceMock = () => createTelemetryClientMock(); +export const createTelemetryServiceMock = () => ({ reportEvent: jest.fn() }); diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts index 9079c6bf4f65..486aa241290a 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts @@ -8,7 +8,7 @@ import { coreMock } from '@kbn/core/server/mocks'; import { telemetryEvents } from './events/telemetry_events'; import { TelemetryService } from './telemetry_service'; -import { TelemetryEventTypes } from './constants'; +import { AlertsEventTypes } from './types'; describe('TelemetryService', () => { let service: TelemetryService; @@ -41,17 +41,12 @@ describe('TelemetryService', () => { }); describe('#start()', () => { - it('should return all the available tracking methods', () => { + it('should return the tracking method', () => { const setupParams = getSetupParams(); service.setup(setupParams); const telemetry = service.start(); - expect(telemetry).toHaveProperty('reportAlertsGroupingChanged'); - expect(telemetry).toHaveProperty('reportAlertsGroupingToggled'); - expect(telemetry).toHaveProperty('reportAlertsGroupingTakeAction'); - - expect(telemetry).toHaveProperty('reportDetailsFlyoutOpened'); - expect(telemetry).toHaveProperty('reportDetailsFlyoutTabClicked'); + expect(telemetry).toHaveProperty('reportEvent'); }); }); @@ -61,7 +56,7 @@ describe('TelemetryService', () => { service.setup(setupParams); const telemetry = service.start(); - telemetry.reportAlertsGroupingTakeAction({ + telemetry.reportEvent(AlertsEventTypes.AlertsGroupingTakeAction, { tableId: 'test-groupingId', groupNumber: 0, status: 'closed', @@ -70,7 +65,7 @@ describe('TelemetryService', () => { expect(setupParams.analytics.reportEvent).toHaveBeenCalledTimes(1); expect(setupParams.analytics.reportEvent).toHaveBeenCalledWith( - TelemetryEventTypes.AlertsGroupingTakeAction, + AlertsEventTypes.AlertsGroupingTakeAction, { tableId: 'test-groupingId', groupNumber: 0, diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.ts index d4c100d5fe40..a1bf49394af9 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.ts @@ -8,13 +8,18 @@ import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; import { of } from 'rxjs'; import type { + TelemetryEventTypeData, + TelemetryEventTypes, TelemetryServiceSetupParams, - TelemetryClientStart, - TelemetryEventParams, } from './types'; import { telemetryEvents } from './events/telemetry_events'; -import { TelemetryClient } from './telemetry_client'; +export interface TelemetryServiceStart { + reportEvent: ( + eventType: T, + eventData: TelemetryEventTypeData + ) => void; +} /** * Service that interacts with the Core's analytics module * to trigger custom event for Security Solution plugin features @@ -41,17 +46,19 @@ export class TelemetryService { }); } telemetryEvents.forEach((eventConfig) => - analytics.registerEventType(eventConfig) + analytics.registerEventType>(eventConfig) ); } - public start(): TelemetryClientStart { - if (!this.analytics) { + public start(): TelemetryServiceStart { + const reportEvent = this.analytics?.reportEvent.bind(this.analytics); + + if (!this.analytics || !reportEvent) { throw new Error( 'The TelemetryService.setup() method has not been invoked, be sure to call it during the plugin setup.' ); } - return new TelemetryClient(this.analytics); + return { reportEvent }; } } diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts index 95896bf74a6a..9cd56ebcb60f 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/types.ts @@ -5,77 +5,41 @@ * 2.0. */ -import type { AnalyticsServiceSetup, RootSchema } from '@kbn/core/public'; -import type { SecurityCellActionMetadata } from '../../../app/actions/types'; -import type { ML_JOB_TELEMETRY_STATUS, TelemetryEventTypes } from './constants'; +import type { AnalyticsServiceSetup } from '@kbn/core/public'; import type { - AlertsGroupingTelemetryEvent, - ReportAlertsGroupingChangedParams, - ReportAlertsGroupingTelemetryEventParams, - ReportAlertsGroupingToggledParams, - ReportAlertsTakeActionParams, + AlertsEventTypes, + AlertsGroupingTelemetryEventsMap, } from './events/alerts_grouping/types'; import type { - ReportDataQualityCheckAllCompletedParams, - ReportDataQualityIndexCheckedParams, - DataQualityTelemetryEvents, + DataQualityEventTypes, + DataQualityTelemetryEventsMap, } from './events/data_quality/types'; import type { - EntityAnalyticsTelemetryEvent, - ReportAddRiskInputToTimelineClickedParams, - ReportEntityAlertsClickedParams, - ReportEntityAnalyticsTelemetryEventParams, - ReportEntityDetailsClickedParams, - ReportEntityRiskFilteredParams, - ReportRiskInputsExpandedFlyoutOpenedParams, - ReportToggleRiskSummaryClickedParams, - ReportAssetCriticalityCsvPreviewGeneratedParams, - ReportAssetCriticalityFileSelectedParams, - ReportAssetCriticalityCsvImportedParams, - ReportEntityStoreEnablementParams, - ReportEntityStoreInitParams, + EntityAnalyticsTelemetryEventsMap, + EntityEventTypes, } from './events/entity_analytics/types'; +import type { AssistantEventTypes, AssistantTelemetryEventsMap } from './events/ai_assistant/types'; import type { - AssistantTelemetryEvent, - ReportAssistantTelemetryEventParams, - ReportAssistantInvokedParams, - ReportAssistantQuickPromptParams, - ReportAssistantMessageSentParams, - ReportAssistantSettingToggledParams, -} from './events/ai_assistant/types'; -import type { - DocumentDetailsTelemetryEvents, - ReportDocumentDetailsTelemetryEventParams, - ReportDetailsFlyoutOpenedParams, - ReportDetailsFlyoutTabClickedParams, + DocumentDetailsTelemetryEventsMap, + DocumentEventTypes, } from './events/document_details/types'; import type { - OnboardingHubStepFinishedParams, - OnboardingHubStepLinkClickedParams, - OnboardingHubStepOpenParams, - OnboardingHubTelemetryEvent, + OnboardingHubEventTypes, + OnboardingHubTelemetryEventsMap, } from './events/onboarding/types'; import type { - ManualRuleRunTelemetryEvent, - ReportManualRuleRunOpenModalParams, - ReportManualRuleRunExecuteParams, - ReportManualRuleRunCancelJobParams, - ReportManualRuleRunTelemetryEventParams, + ManualRuleRunEventTypes, + ManualRuleRunTelemetryEventsMap, } from './events/manual_rule_run/types'; +import type { EventLogEventTypes, EventLogTelemetryEventsMap } from './events/event_log/types'; +import type { NotesEventTypes, NotesTelemetryEventsMap } from './events/notes/types'; import type { - EventLogTelemetryEvent, - ReportEventLogFilterByRunTypeParams, - ReportEventLogShowSourceEventDateRangeParams, - ReportEventLogTelemetryEventParams, -} from './events/event_log/types'; -import type { - AddNoteFromExpandableFlyoutClickedParams, - NotesTelemetryEventParams, - NotesTelemetryEvents, - OpenNoteInExpandableFlyoutClickedParams, -} from './events/notes/types'; -import type { PreviewRuleParams, PreviewRuleTelemetryEvent } from './events/preview_rule/types'; + PreviewRuleEventTypes, + PreviewRuleTelemetryEventsMap, +} from './events/preview_rule/types'; +import type { AppEventTypes, AppTelemetryEventsMap } from './events/app/types'; +export * from './events/app/types'; export * from './events/ai_assistant/types'; export * from './events/alerts_grouping/types'; export * from './events/data_quality/types'; @@ -85,142 +49,46 @@ export * from './events/document_details/types'; export * from './events/manual_rule_run/types'; export * from './events/event_log/types'; export * from './events/preview_rule/types'; +export * from './events/notes/types'; export interface TelemetryServiceSetupParams { analytics: AnalyticsServiceSetup; } -export interface ReportMLJobUpdateParams { - jobId: string; - isElasticJob: boolean; - status: ML_JOB_TELEMETRY_STATUS; - moduleId?: string; - errorMessage?: string; -} - -export interface ReportCellActionClickedParams { - metadata: SecurityCellActionMetadata | undefined; - displayName: string; - actionId: string; - fieldName: string; -} - -export interface ReportAnomaliesCountClickedParams { - jobId: string; - count: number; -} - -export interface ReportBreadcrumbClickedParams { - title: string; -} - -export type TelemetryEventParams = - | ReportAlertsGroupingTelemetryEventParams - | ReportAssistantTelemetryEventParams - | ReportEntityAnalyticsTelemetryEventParams - | ReportMLJobUpdateParams - | ReportCellActionClickedParams - | ReportAnomaliesCountClickedParams - | ReportDataQualityIndexCheckedParams - | ReportDataQualityCheckAllCompletedParams - | ReportBreadcrumbClickedParams - | ReportDocumentDetailsTelemetryEventParams - | OnboardingHubStepOpenParams - | OnboardingHubStepFinishedParams - | OnboardingHubStepLinkClickedParams - | ReportManualRuleRunTelemetryEventParams - | ReportEventLogTelemetryEventParams - | PreviewRuleParams - | NotesTelemetryEventParams; - -export interface TelemetryClientStart { - reportAlertsGroupingChanged(params: ReportAlertsGroupingChangedParams): void; - reportAlertsGroupingToggled(params: ReportAlertsGroupingToggledParams): void; - reportAlertsGroupingTakeAction(params: ReportAlertsTakeActionParams): void; - - // Assistant - reportAssistantInvoked(params: ReportAssistantInvokedParams): void; - reportAssistantMessageSent(params: ReportAssistantMessageSentParams): void; - reportAssistantQuickPrompt(params: ReportAssistantQuickPromptParams): void; - reportAssistantSettingToggled(params: ReportAssistantSettingToggledParams): void; - - // Entity Analytics - reportEntityDetailsClicked(params: ReportEntityDetailsClickedParams): void; - reportEntityAlertsClicked(params: ReportEntityAlertsClickedParams): void; - reportEntityRiskFiltered(params: ReportEntityRiskFilteredParams): void; - reportMLJobUpdate(params: ReportMLJobUpdateParams): void; - // Entity Analytics inside Entity Flyout - reportToggleRiskSummaryClicked(params: ReportToggleRiskSummaryClickedParams): void; - reportRiskInputsExpandedFlyoutOpened(params: ReportRiskInputsExpandedFlyoutOpenedParams): void; - reportAddRiskInputToTimelineClicked(params: ReportAddRiskInputToTimelineClickedParams): void; - // Entity Analytics Asset Criticality - reportAssetCriticalityFileSelected(params: ReportAssetCriticalityFileSelectedParams): void; - reportAssetCriticalityCsvPreviewGenerated( - params: ReportAssetCriticalityCsvPreviewGeneratedParams - ): void; - reportAssetCriticalityCsvImported(params: ReportAssetCriticalityCsvImportedParams): void; - reportCellActionClicked(params: ReportCellActionClickedParams): void; - // Entity Analytics Entity Store - reportEntityStoreEnablement(params: ReportEntityStoreEnablementParams): void; - reportEntityStoreInit(params: ReportEntityStoreInitParams): void; - - reportAnomaliesCountClicked(params: ReportAnomaliesCountClickedParams): void; - reportDataQualityIndexChecked(params: ReportDataQualityIndexCheckedParams): void; - reportDataQualityCheckAllCompleted(params: ReportDataQualityCheckAllCompletedParams): void; - reportBreadcrumbClicked(params: ReportBreadcrumbClickedParams): void; - - // document details flyout - reportDetailsFlyoutOpened(params: ReportDetailsFlyoutOpenedParams): void; - reportDetailsFlyoutTabClicked(params: ReportDetailsFlyoutTabClickedParams): void; - - // onboarding hub - reportOnboardingHubStepOpen(params: OnboardingHubStepOpenParams): void; - reportOnboardingHubStepFinished(params: OnboardingHubStepFinishedParams): void; - reportOnboardingHubStepLinkClicked(params: OnboardingHubStepLinkClickedParams): void; - - // manual rule run - reportManualRuleRunOpenModal(params: ReportManualRuleRunOpenModalParams): void; - reportManualRuleRunExecute(params: ReportManualRuleRunExecuteParams): void; - reportManualRuleRunCancelJob(params: ReportManualRuleRunCancelJobParams): void; - - // event log - reportEventLogFilterByRunType(params: ReportEventLogFilterByRunTypeParams): void; - reportEventLogShowSourceEventDateRange( - params: ReportEventLogShowSourceEventDateRangeParams - ): void; - - // new notes - reportOpenNoteInExpandableFlyoutClicked(params: OpenNoteInExpandableFlyoutClickedParams): void; - reportAddNoteFromExpandableFlyoutClicked(params: AddNoteFromExpandableFlyoutClickedParams): void; - - // preview rule - reportPreviewRule(params: PreviewRuleParams): void; -} - -export type TelemetryEvent = - | AssistantTelemetryEvent - | AlertsGroupingTelemetryEvent - | EntityAnalyticsTelemetryEvent - | DataQualityTelemetryEvents - | DocumentDetailsTelemetryEvents - | { - eventType: TelemetryEventTypes.MLJobUpdate; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.CellActionClicked; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.AnomaliesCountClicked; - schema: RootSchema; - } - | { - eventType: TelemetryEventTypes.BreadcrumbClicked; - schema: RootSchema; - } - | OnboardingHubTelemetryEvent - | ManualRuleRunTelemetryEvent - | EventLogTelemetryEvent - | PreviewRuleTelemetryEvent - | NotesTelemetryEvents; +// Combine all event type data +export type TelemetryEventTypeData = T extends AssistantEventTypes + ? AssistantTelemetryEventsMap[T] + : T extends AlertsEventTypes + ? AlertsGroupingTelemetryEventsMap[T] + : T extends PreviewRuleEventTypes + ? PreviewRuleTelemetryEventsMap[T] + : T extends EntityEventTypes + ? EntityAnalyticsTelemetryEventsMap[T] + : T extends DataQualityEventTypes + ? DataQualityTelemetryEventsMap[T] + : T extends DocumentEventTypes + ? DocumentDetailsTelemetryEventsMap[T] + : T extends OnboardingHubEventTypes + ? OnboardingHubTelemetryEventsMap[T] + : T extends ManualRuleRunEventTypes + ? ManualRuleRunTelemetryEventsMap[T] + : T extends EventLogEventTypes + ? EventLogTelemetryEventsMap[T] + : T extends NotesEventTypes + ? NotesTelemetryEventsMap[T] + : T extends AppEventTypes + ? AppTelemetryEventsMap[T] + : never; + +export type TelemetryEventTypes = + | AssistantEventTypes + | AlertsEventTypes + | PreviewRuleEventTypes + | EntityEventTypes + | DataQualityEventTypes + | DocumentEventTypes + | OnboardingHubEventTypes + | ManualRuleRunEventTypes + | EventLogEventTypes + | NotesEventTypes + | AppEventTypes; diff --git a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx index b42dbc3b7a0b..23abdab4d14f 100644 --- a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx @@ -283,7 +283,7 @@ export const createAppRootMockRenderer = (): AppContextTestRender => { }, }); - const AppWrapper: React.FC<{ children: React.ReactElement }> = ({ children }) => ( + const AppWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( { + it('should return the correct value', () => { + const data: TimelineNonEcsData[] = [{ field: 'field1', value: ['value1'] }]; + const fieldName = 'field1'; + const result = getMappedNonEcsValue({ data, fieldName }); + expect(result).toEqual(['value1']); + }); + + it('should return undefined if item is null', () => { + const data: TimelineNonEcsData[] = [{ field: 'field1', value: ['value1'] }]; + const fieldName = 'field2'; + const result = getMappedNonEcsValue({ data, fieldName }); + expect(result).toEqual(undefined); + }); + + it('should return undefined if item.value is null', () => { + const data: TimelineNonEcsData[] = [{ field: 'field1', value: null }]; + const fieldName = 'non_existent_field'; + const result = getMappedNonEcsValue({ data, fieldName }); + expect(result).toEqual(undefined); + }); + + it('should return undefined if data is undefined', () => { + const data = undefined; + const fieldName = 'field1'; + const result = getMappedNonEcsValue({ data, fieldName }); + expect(result).toEqual(undefined); + }); + + it('should return undefined if data is empty', () => { + const data: TimelineNonEcsData[] = []; + const fieldName = 'field1'; + const result = getMappedNonEcsValue({ data, fieldName }); + expect(result).toEqual(undefined); + }); +}); + +describe('useGetMappedNonEcsValue', () => { + it('should return the correct value', () => { + const data: TimelineNonEcsData[] = [{ field: 'field1', value: ['value1'] }]; + const fieldName = 'field1'; + const { result } = renderHook(() => useGetMappedNonEcsValue({ data, fieldName })); + expect(result.current).toEqual(['value1']); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/utils/get_mapped_non_ecs_value.ts b/x-pack/plugins/security_solution/public/common/utils/get_mapped_non_ecs_value.ts new file mode 100644 index 000000000000..e0711127e1e4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/utils/get_mapped_non_ecs_value.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 type { TimelineNonEcsData } from '@kbn/timelines-plugin/common'; +import { useMemo } from 'react'; + +export const getMappedNonEcsValue = ({ + data, + fieldName, +}: { + data?: TimelineNonEcsData[]; + fieldName: string; +}): string[] | undefined => { + /* + While data _should_ always be defined + There is the potential for race conditions where a component using this function + is still visible in the UI, while the data has since been removed. + To cover all scenarios where this happens we'll check for the presence of data here + */ + if (!data || data.length === 0) return undefined; + const item = data.find((d) => d.field === fieldName); + if (item != null && item.value != null) { + return item.value; + } + return undefined; +}; + +export const useGetMappedNonEcsValue = ({ + data, + fieldName, +}: { + data?: TimelineNonEcsData[]; + fieldName: string; +}): string[] | undefined => { + return useMemo(() => getMappedNonEcsValue({ data, fieldName }), [data, fieldName]); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/related_integrations/related_integrations.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/related_integrations/related_integrations.test.tsx index dd08cae462a0..960df4c7de5b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/related_integrations/related_integrations.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/related_integrations/related_integrations.test.tsx @@ -499,6 +499,9 @@ describe('RelatedIntegrations form part', () => { comboBoxToggleButton: screen.getByTestId(COMBO_BOX_TOGGLE_BUTTON_TEST_ID), optionIndex: 0, }); + await waitFor(() => { + expect(screen.getByTestId(VERSION_INPUT_TEST_ID)).toHaveValue('^1.2.0'); + }); await setVersion({ input: screen.getByTestId(VERSION_INPUT_TEST_ID), value: '1.0.0' }); await submitForm(); await waitFor(() => { @@ -614,6 +617,9 @@ describe('RelatedIntegrations form part', () => { await selectFirstEuiComboBoxOption({ comboBoxToggleButton: screen.getByTestId(COMBO_BOX_TOGGLE_BUTTON_TEST_ID), }); + await waitFor(() => { + expect(screen.getByTestId(VERSION_INPUT_TEST_ID)).toHaveValue('^1.0.0'); + }); await setVersion({ input: screen.getByTestId(VERSION_INPUT_TEST_ID), value: '100' }); expect(screen.getByTestId(RELATED_INTEGRATION_ROW)).toHaveTextContent( diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/make_validate_required_field.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/make_validate_required_field.ts index 7402f55a47e5..26ddcc5f61c1 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/make_validate_required_field.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/make_validate_required_field.ts @@ -6,8 +6,9 @@ */ import type { RequiredFieldInput } from '../../../../../common/api/detection_engine/model/rule_schema/common_attributes.gen'; -import type { ERROR_CODE, FormData, ValidationFunc } from '../../../../shared_imports'; +import type { ERROR_CODE, FormData, FormHook, ValidationFunc } from '../../../../shared_imports'; import * as i18n from './translations'; +import { getFlattenedArrayFieldNames } from './utils'; export function makeValidateRequiredField(parentFieldPath: string) { return function validateRequiredField( @@ -15,11 +16,10 @@ export function makeValidateRequiredField(parentFieldPath: string) { ): ReturnType> | undefined { const [{ value, path, form }] = args; - const formData = form.getFormData(); - const parentFieldData: RequiredFieldInput[] = formData[parentFieldPath]; + const allRequiredFields = getAllRequiredFieldsValues(form, parentFieldPath); const isFieldNameUsedMoreThanOnce = - parentFieldData.filter((field) => field.name === value.name).length > 1; + allRequiredFields.filter((field) => field.name === value.name).length > 1; if (isFieldNameUsedMoreThanOnce) { return { @@ -51,3 +51,20 @@ export function makeValidateRequiredField(parentFieldPath: string) { } }; } + +function getAllRequiredFieldsValues( + form: { getFields: FormHook['getFields'] }, + parentFieldPath: string +) { + /* + Getting values for required fields via flattened fields instead of using `getFormData`. + This is because `getFormData` applies a serializer function to field values, which might update values. + Using flattened fields allows us to get the original values before the serializer function is applied. + */ + const flattenedFieldNames = getFlattenedArrayFieldNames(form, parentFieldPath); + const fields = form.getFields(); + + return flattenedFieldNames.map( + (fieldName) => fields[fieldName]?.value ?? {} + ) as RequiredFieldInput[]; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/required_fields.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/required_fields.tsx index f53c41ce98d0..f2f4c08a3581 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/required_fields.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/required_fields.tsx @@ -16,6 +16,7 @@ import { RequiredFieldsHelpInfo } from './required_fields_help_info'; import { RequiredFieldRow } from './required_fields_row'; import * as defineRuleI18n from '../../../rule_creation_ui/components/step_define_rule/translations'; import * as i18n from './translations'; +import { getFlattenedArrayFieldNames } from './utils'; interface RequiredFieldsComponentProps { path: string; @@ -65,7 +66,7 @@ const RequiredFieldsList = ({ form, }: RequiredFieldsListProps) => { /* - This component should only re-render when either the "index" form field (index patterns) or the required fields change. + This component should only re-render when either the "index" form field (index patterns) or the required fields change. By default, the `useFormData` hook triggers a re-render whenever any form field changes. It also allows optimization by passing a "watch" array of field names. The component then only re-renders when these specified fields change. @@ -77,10 +78,7 @@ const RequiredFieldsList = ({ To work around this, we manually construct a list of "flattened" field names to watch, based on the current state of the form. This is a temporary solution and ideally, `useFormData` should be updated to handle this scenario. */ - - const internalField = form.getFields()[`${path}__array__`] ?? {}; - const internalFieldValue = (internalField?.value ?? []) as ArrayItem[]; - const flattenedFieldNames = internalFieldValue.map((item) => item.path); + const flattenedFieldNames = getFlattenedArrayFieldNames(form, path); /* Not using "watch" for the initial render, to let row components render and initialize form fields. diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/required_fields_row.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/required_fields_row.tsx index 755f1de41376..39b08ac17e49 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/required_fields_row.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/required_fields_row.tsx @@ -44,14 +44,6 @@ export const RequiredFieldRow = ({ const rowFieldConfig: FieldConfig = useMemo( () => ({ - deserializer: (value) => { - const rowValueWithoutEcs: RequiredFieldInput = { - name: value.name, - type: value.type, - }; - - return rowValueWithoutEcs; - }, validations: [{ validator: makeValidateRequiredField(parentFieldPath) }], defaultValue: { name: '', type: '' }, }), diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/utils.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/utils.ts index 55beca264e12..38820e992fa6 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/utils.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/required_fields/utils.ts @@ -5,6 +5,8 @@ * 2.0. */ +import type { FormHook, ArrayItem } from '../../../../shared_imports'; + interface PickTypeForNameParameters { name: string; type: string; @@ -26,3 +28,26 @@ export function pickTypeForName({ name, type, typesByFieldName = {} }: PickTypeF */ return typesAvailableForName[0] ?? type; } + +/** + * Returns a list of flattened field names for a given array field of a form. + * Flattened field name is a string that represents the path to an item in an array field. + * For example, a field "myArrayField" can be represented as "myArrayField[0]", "myArrayField[1]", etc. + * + * Flattened field names are useful: + * - when you need to subscribe to changes in an array field using `useFormData` "watch" option + * - when you need to retrieve form data before serializer function is applied + * + * @param {Object} form - Form object. + * @param {string} arrayFieldName - Path to the array field. + * @returns {string[]} - Flattened array field names. + */ +export function getFlattenedArrayFieldNames( + form: { getFields: FormHook['getFields'] }, + arrayFieldName: string +): string[] { + const internalField = form.getFields()[`${arrayFieldName}__array__`] ?? {}; + const internalFieldValue = (internalField?.value ?? []) as ArrayItem[]; + + return internalFieldValue.map((item) => item.path); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/autocomplete_field/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/es_field_selector_field/index.tsx similarity index 70% rename from x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/autocomplete_field/index.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/es_field_selector_field/index.tsx index 37c19f5724ec..03d0a3021dc3 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/autocomplete_field/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/es_field_selector_field/index.tsx @@ -7,13 +7,13 @@ import React, { useCallback, useMemo } from 'react'; import { EuiFormRow } from '@elastic/eui'; -import { FieldComponent } from '@kbn/securitysolution-autocomplete'; +import { EsFieldSelector } from '@kbn/securitysolution-autocomplete'; import type { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; import type { FieldHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -interface AutocompleteFieldProps { +interface EsFieldSelectorFieldProps { dataTestSubj: string; - field: FieldHook; + field: FieldHook; idAria: string; indices: DataViewBase; isDisabled: boolean; @@ -21,7 +21,7 @@ interface AutocompleteFieldProps { placeholder?: string; } -export const AutocompleteField = ({ +export const EsFieldSelectorField = ({ dataTestSubj, field, idAria, @@ -29,35 +29,37 @@ export const AutocompleteField = ({ isDisabled, fieldType, placeholder, -}: AutocompleteFieldProps) => { +}: EsFieldSelectorFieldProps) => { + const fieldTypeFilter = useMemo(() => [fieldType], [fieldType]); + const handleFieldChange = useCallback( ([newField]: DataViewFieldBase[]): void => { - // TODO: Update onChange type in FieldComponent as newField can be undefined field.setValue(newField?.name ?? ''); }, [field] ); - const selectedField = useMemo(() => { - const existingField = (field.value as string) ?? ''; - const [newSelectedField] = indices.fields.filter( - ({ name }) => existingField != null && existingField === name - ); - return newSelectedField; - }, [field.value, indices]); + const selectedField = useMemo( + () => + indices.fields.find(({ name }) => field.value === name) ?? { + name: field.value, + type: fieldType, + }, + [field.value, indices, fieldType] + ); - const fieldTypeFilter = useMemo(() => [fieldType], [fieldType]); + const describedByIds = useMemo(() => (idAria ? [idAria] : undefined), [idAria]); return ( - = ({ const { alerting } = useKibana().services; const maxAlertsPerRun = alerting.getMaxAlertsPerRun(); - const [isInvalid, error] = useMemo(() => { - if (typeof value === 'number' && !isNaN(value) && value <= 0) { - return [true, i18n.GREATER_THAN_ERROR]; - } - return [false]; - }, [value]); + const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); const hasWarning = useMemo( () => typeof value === 'number' && !isNaN(value) && value > maxAlertsPerRun, @@ -67,6 +66,8 @@ export const MaxSignals: React.FC = ({ return textToRender; }, [hasWarning, maxAlertsPerRun]); + const describedByIds = useMemo(() => (idAria ? [idAria] : undefined), [idAria]); + return ( = ({ width: ${MAX_SIGNALS_FIELD_WIDTH}px; } `} - describedByIds={idAria ? [idAria] : undefined} + describedByIds={describedByIds} fullWidth helpText={helpText} label={field.label} labelAppend={field.labelAppend} isInvalid={isInvalid} - error={error} + error={errorMessage} > = ({ data-test-subj={dataTestSubj} disabled={isDisabled} append={hasWarning ? : undefined} + min={MIN_VALUE} /> ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/max_signals/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/max_signals/translations.ts index b69c0557a051..b5b135d456f3 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/max_signals/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/max_signals/translations.ts @@ -7,13 +7,6 @@ import { i18n } from '@kbn/i18n'; -export const GREATER_THAN_ERROR = i18n.translate( - 'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.maxAlertsFieldGreaterThanError', - { - defaultMessage: 'Max alerts must be greater than 0.', - } -); - export const LESS_THAN_WARNING = (maxNumber: number) => i18n.translate( 'xpack.securitySolution.detectionEngine.createRule.stepAboutRule.maxAlertsFieldLessThanWarning', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/risk_score_mapping/default_risk_score.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/risk_score_mapping/default_risk_score.tsx new file mode 100644 index 000000000000..94899f35e272 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/risk_score_mapping/default_risk_score.tsx @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback } from 'react'; +import { EuiFormRow, EuiText, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiRange } from '@elastic/eui'; +import type { EuiRangeProps } from '@elastic/eui'; +import { MAX_RISK_SCORE, MIN_RISK_SCORE } from '../../validators/default_risk_score_validator'; +import * as i18n from './translations'; + +interface DefaultRiskScoreProps { + value: number; + onChange: (newValue: number) => void; + errorMessage?: string; + idAria?: string; + dataTestSubj?: string; +} + +export function DefaultRiskScore({ + value, + onChange, + errorMessage, + idAria, + dataTestSubj = 'defaultRiskScore', +}: DefaultRiskScoreProps) { + const handleChange = useCallback>( + (event) => { + const eventValue = (event.target as HTMLInputElement).value; + const intOrNanValue = Number.parseInt(eventValue.trim(), 10); + const intValue = Number.isNaN(intOrNanValue) ? MIN_RISK_SCORE : intOrNanValue; + + onChange(intValue); + }, + [onChange] + ); + + return ( + + } + error={errorMessage} + isInvalid={!!errorMessage} + fullWidth + data-test-subj={`${dataTestSubj}-defaultRisk`} + describedByIds={idAria ? [idAria] : undefined} + > + + + + ); +} + +function DefaultRiskScoreLabel() { + return ( +
    + + {i18n.DEFAULT_RISK_SCORE} + + + {i18n.RISK_SCORE_DESCRIPTION} +
    + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/risk_score_mapping/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/risk_score_mapping/index.tsx index 1cd775c2e80e..d5360bbf0400 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/risk_score_mapping/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/risk_score_mapping/index.tsx @@ -5,45 +5,16 @@ * 2.0. */ -import React, { useCallback, useMemo } from 'react'; -import styled from 'styled-components'; -import { noop } from 'lodash/fp'; -import { - EuiFormRow, - EuiCheckbox, - EuiText, - EuiFlexGroup, - EuiFlexItem, - EuiFormLabel, - EuiIcon, - EuiSpacer, - EuiRange, -} from '@elastic/eui'; -import type { EuiRangeProps } from '@elastic/eui'; - +import React, { useCallback } from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import type { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; -import type { FieldHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { FieldComponent } from '@kbn/securitysolution-autocomplete'; -import type { RiskScoreMapping } from '@kbn/securitysolution-io-ts-alerting-types'; - +import { + getFieldValidityAndErrorMessage, + type FieldHook, +} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import type { AboutStepRiskScore } from '../../../../detections/pages/detection_engine/rules/types'; -import * as i18n from './translations'; - -const NestedContent = styled.div` - margin-left: 24px; -`; - -const EuiFlexItemComboBoxColumn = styled(EuiFlexItem)` - max-width: 376px; -`; - -const EuiFlexItemIconColumn = styled(EuiFlexItem)` - width: 20px; -`; - -const EuiFlexItemRiskScoreColumn = styled(EuiFlexItem)` - width: 160px; -`; +import { DefaultRiskScore } from './default_risk_score'; +import { RiskScoreOverride } from './risk_score_override'; interface RiskScoreFieldProps { dataTestSubj: string; @@ -51,7 +22,6 @@ interface RiskScoreFieldProps { idAria: string; indices: DataViewBase; isDisabled: boolean; - placeholder?: string; } export const RiskScoreField = ({ @@ -60,19 +30,14 @@ export const RiskScoreField = ({ idAria, indices, isDisabled, - placeholder, }: RiskScoreFieldProps) => { const { value, isMappingChecked, mapping } = field.value; const { setValue } = field; - const fieldTypeFilter = useMemo(() => ['number'], []); - const selectedField = useMemo(() => getFieldTypeByMapping(mapping, indices), [mapping, indices]); - - const handleDefaultRiskScoreChange = useCallback>( - (e) => { - const range = (e.target as HTMLInputElement).value; + const handleDefaultRiskScoreChange = useCallback( + (newDefaultRiskScoreValue: number) => { setValue({ - value: Number(range.trim()), + value: newDefaultRiskScoreValue, isMappingChecked, mapping, }); @@ -106,146 +71,29 @@ export const RiskScoreField = ({ }); }, [setValue, value, isMappingChecked, mapping]); - const riskScoreLabel = useMemo(() => { - return ( -
    - - {i18n.DEFAULT_RISK_SCORE} - - - {i18n.RISK_SCORE_DESCRIPTION} -
    - ); - }, []); - - const riskScoreMappingLabel = useMemo(() => { - return ( -
    - - - - - {i18n.RISK_SCORE_MAPPING} - - - - {i18n.RISK_SCORE_MAPPING_DESCRIPTION} - -
    - ); - }, [isMappingChecked, handleRiskScoreMappingChecked, isDisabled]); + const errorMessage = getFieldValidityAndErrorMessage(field).errorMessage ?? undefined; return ( + - - - - - - {i18n.RISK_SCORE_MAPPING_DETAILS} : '' - } - error={'errorMessage'} - isInvalid={false} - fullWidth - data-test-subj={`${dataTestSubj}-riskOverride`} - describedByIds={idAria ? [idAria] : undefined} - > - - - {isMappingChecked && ( - - - - - {i18n.SOURCE_FIELD} - - - - {i18n.DEFAULT_RISK_SCORE} - - - - - - - - - - - - - - {i18n.RISK_SCORE_FIELD} - - - - - )} - - + ); }; - -/** - * Looks for field metadata (DataViewFieldBase) in existing index pattern. - * If specified field doesn't exist, returns a stub DataViewFieldBase created based on the mapping -- - * because the field might not have been indexed yet, but we still need to display the mapping. - * - * @param mapping Mapping of a specified field name to risk score. - * @param pattern Existing index pattern. - */ -const getFieldTypeByMapping = ( - mapping: RiskScoreMapping, - pattern: DataViewBase -): DataViewFieldBase => { - const field = mapping?.[0]?.field ?? ''; - const [knownFieldType] = pattern.fields.filter(({ name }) => field != null && field === name); - return knownFieldType ?? { name: field, type: 'number' }; -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/risk_score_mapping/risk_score_override.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/risk_score_mapping/risk_score_override.tsx new file mode 100644 index 000000000000..d6067062685f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/risk_score_mapping/risk_score_override.tsx @@ -0,0 +1,163 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import { noop } from 'lodash/fp'; +import styled from 'styled-components'; +import { + EuiFormRow, + EuiCheckbox, + EuiText, + EuiFlexGroup, + EuiFlexItem, + EuiFormLabel, + EuiIcon, + EuiSpacer, +} from '@elastic/eui'; +import type { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; +import { EsFieldSelector } from '@kbn/securitysolution-autocomplete'; +import * as i18n from './translations'; +import type { RiskScoreMapping } from '../../../../../common/api/detection_engine'; + +const NestedContent = styled.div` + margin-left: 24px; +`; + +const EuiFlexItemComboBoxColumn = styled(EuiFlexItem)` + max-width: 376px; +`; + +const EuiFlexItemIconColumn = styled(EuiFlexItem)` + width: 20px; +`; + +const EuiFlexItemRiskScoreColumn = styled(EuiFlexItem)` + width: 160px; +`; + +const fieldTypeFilter = ['number']; + +interface RiskScoreOverrideProps { + isMappingChecked: boolean; + onToggleMappingChecked: () => void; + onMappingChange: ([newField]: DataViewFieldBase[]) => void; + mapping: RiskScoreMapping; + indices: DataViewBase; + dataTestSubj?: string; + idAria?: string; + isDisabled: boolean; +} + +export function RiskScoreOverride({ + isMappingChecked, + onToggleMappingChecked, + onMappingChange, + mapping, + indices, + dataTestSubj = 'riskScoreOverride', + idAria, + isDisabled, +}: RiskScoreOverrideProps) { + const riskScoreMappingLabel = useMemo(() => { + return ( +
    + + + + + {i18n.RISK_SCORE_MAPPING} + + + + {i18n.RISK_SCORE_MAPPING_DESCRIPTION} + +
    + ); + }, [isDisabled, isMappingChecked, onToggleMappingChecked]); + + const describedByIds = useMemo(() => (idAria ? [idAria] : undefined), [idAria]); + const selectedField = useMemo(() => getFieldTypeByMapping(mapping, indices), [mapping, indices]); + + return ( + {i18n.RISK_SCORE_MAPPING_DETAILS} : '' + } + fullWidth + data-test-subj={`${dataTestSubj}-riskOverride`} + describedByIds={describedByIds} + > + + + {isMappingChecked && ( + + + + + {i18n.SOURCE_FIELD} + + + + {i18n.DEFAULT_RISK_SCORE} + + + + + + + + + + + + + + {i18n.RISK_SCORE_FIELD} + + + + + )} + + + ); +} + +/** + * Looks for field metadata (DataViewFieldBase) in existing index pattern. + * If specified field doesn't exist, returns a stub DataViewFieldBase created based on the mapping -- + * because the field might not have been indexed yet, but we still need to display the mapping. + * + * @param mapping Mapping of a specified field name to risk score. + * @param pattern Existing index pattern. + */ +const getFieldTypeByMapping = ( + mapping: RiskScoreMapping, + pattern: DataViewBase +): DataViewFieldBase => { + const field = mapping?.[0]?.field ?? ''; + const [knownFieldType] = pattern.fields.filter(({ name }) => field != null && field === name); + return knownFieldType ?? { name: field, type: 'number' }; +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/use_preview_rule.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/use_preview_rule.ts index 018e2602aa17..79257b4fef3d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/use_preview_rule.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/use_preview_rule.ts @@ -18,6 +18,7 @@ import { transformOutput } from '../../../../detections/containers/detection_eng import type { TimeframePreviewOptions } from '../../../../detections/pages/detection_engine/rules/types'; import { usePreviewInvocationCount } from './use_preview_invocation_count'; import * as i18n from './translations'; +import { PreviewRuleEventTypes } from '../../../../common/lib/telemetry'; const emptyPreviewRule: RulePreviewResponse = { previewId: undefined, @@ -58,7 +59,7 @@ export const usePreviewRule = ({ const createPreviewId = async () => { if (rule != null) { try { - telemetry.reportPreviewRule({ + telemetry.reportEvent(PreviewRuleEventTypes.PreviewRule, { loggedRequestsEnabled: enableLoggedRequests ?? false, ruleType: rule.type, }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/severity_mapping/default_severity.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/severity_mapping/default_severity.tsx new file mode 100644 index 000000000000..477b4bcd0f51 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/severity_mapping/default_severity.tsx @@ -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 { + EuiFormRow, + EuiText, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiSuperSelect, +} from '@elastic/eui'; +import React from 'react'; +import type { Severity } from '../../../../../common/api/detection_engine/model/rule_schema/common_attributes.gen'; +import { severityOptions } from '../step_about_rule/data'; +import * as i18n from './translations'; + +const describedByIds = ['detectionEngineStepAboutRuleSeverity']; + +interface DefaultSeverityProps { + value: Severity; + onChange: (newValue: Severity) => void; +} + +export function DefaultSeverity({ value, onChange }: DefaultSeverityProps) { + return ( + + } + fullWidth + data-test-subj="detectionEngineStepAboutRuleSeverity" + describedByIds={describedByIds} + > + + + + ); +} + +function DefaultSeverityLabel() { + return ( +
    + + {i18n.SEVERITY} + + + {i18n.SEVERITY_DESCRIPTION} +
    + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/severity_mapping/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/severity_mapping/index.tsx index 425564e1ed5f..28d0a2c62241 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/severity_mapping/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/severity_mapping/index.tsx @@ -5,53 +5,14 @@ * 2.0. */ -import { - EuiFormRow, - EuiCheckbox, - EuiText, - EuiFlexGroup, - EuiFlexItem, - EuiFormLabel, - EuiIcon, - EuiSpacer, - EuiSuperSelect, -} from '@elastic/eui'; -import { noop } from 'lodash/fp'; -import React, { useCallback, useMemo } from 'react'; -import styled from 'styled-components'; - +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React, { useCallback } from 'react'; import type { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; import type { FieldHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { - FieldComponent, - AutocompleteFieldMatchComponent, -} from '@kbn/securitysolution-autocomplete'; -import type { - Severity, - SeverityMapping, - SeverityMappingItem, -} from '@kbn/securitysolution-io-ts-alerting-types'; - -import type { SeverityOptionItem } from '../step_about_rule/data'; +import type { Severity, SeverityMapping } from '@kbn/securitysolution-io-ts-alerting-types'; import type { AboutStepSeverity } from '../../../../detections/pages/detection_engine/rules/types'; -import { useKibana } from '../../../../common/lib/kibana'; -import * as i18n from './translations'; - -const NestedContent = styled.div` - margin-left: 24px; -`; - -const EuiFlexItemComboBoxColumn = styled(EuiFlexItem)` - max-width: 376px; -`; - -const EuiFlexItemIconColumn = styled(EuiFlexItem)` - width: 20px; -`; - -const EuiFlexItemSeverityColumn = styled(EuiFlexItem)` - width: 80px; -`; +import { DefaultSeverity } from './default_severity'; +import { SeverityOverride } from './severity_override'; interface SeverityFieldProps { dataTestSubj: string; @@ -59,7 +20,6 @@ interface SeverityFieldProps { idAria: string; indices: DataViewBase; isDisabled: boolean; - options: SeverityOptionItem[]; setRiskScore: (severity: Severity) => void; } @@ -69,10 +29,8 @@ export const SeverityField = ({ idAria, indices, isDisabled, - options, setRiskScore, }: SeverityFieldProps) => { - const { services } = useKibana(); const { value, isMappingChecked, mapping } = field.value; const { setValue } = field; @@ -126,6 +84,7 @@ export const SeverityField = ({ severity, }, ]; + handleFieldValueChange(newMappingItems, index); }, [mapping, handleFieldValueChange] @@ -139,178 +98,22 @@ export const SeverityField = ({ }); }, [isMappingChecked, mapping, value, setValue]); - const severityLabel = useMemo(() => { - return ( -
    - - {i18n.SEVERITY} - - - {i18n.SEVERITY_DESCRIPTION} -
    - ); - }, []); - - const severityMappingLabel = useMemo(() => { - return ( -
    - - - - - {i18n.SEVERITY_MAPPING} - - - - {i18n.SEVERITY_MAPPING_DESCRIPTION} - -
    - ); - }, [handleSeverityMappingChecked, isDisabled, isMappingChecked]); - return ( + - - - - - - - {i18n.SEVERITY_MAPPING_DETAILS} : '' - } - error={'errorMessage'} - isInvalid={false} - fullWidth - data-test-subj={`${dataTestSubj}-severityOverride`} - describedByIds={idAria ? [idAria] : undefined} - > - - - {isMappingChecked && ( - - - - - {i18n.SOURCE_FIELD} - - - {i18n.SOURCE_VALUE} - - - - {i18n.DEFAULT_SEVERITY} - - - - - {mapping.map((severityMappingItem: SeverityMappingItem, index) => ( - - - - - - - - - - - - - - { - options.find((o) => o.value === severityMappingItem.severity) - ?.inputDisplay - } - - - - ))} - - )} - - + ); }; - -/** - * Looks for field metadata (DataViewFieldBase) in existing index pattern. - * If specified field doesn't exist, returns a stub DataViewFieldBase created based on the mapping -- - * because the field might not have been indexed yet, but we still need to display the mapping. - * - * @param mapping Mapping of a specified field name + value to a certain severity value. - * @param pattern Existing index pattern. - */ -const getFieldTypeByMapping = ( - mapping: SeverityMappingItem, - pattern: DataViewBase -): DataViewFieldBase => { - const { field } = mapping; - const [knownFieldType] = pattern.fields.filter(({ name }) => field === name); - return knownFieldType ?? { name: field, type: 'string' }; -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/severity_mapping/severity_override.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/severity_mapping/severity_override.tsx new file mode 100644 index 000000000000..046f360c3af4 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/severity_mapping/severity_override.tsx @@ -0,0 +1,234 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiFormRow, + EuiCheckbox, + EuiText, + EuiFlexGroup, + EuiFlexItem, + EuiFormLabel, + EuiIcon, + EuiSpacer, +} from '@elastic/eui'; +import React, { useCallback, useMemo } from 'react'; +import type { DataViewBase, DataViewFieldBase } from '@kbn/es-query'; +import { + EsFieldSelector, + AutocompleteFieldMatchComponent, +} from '@kbn/securitysolution-autocomplete'; +import type { Severity, SeverityMappingItem } from '@kbn/securitysolution-io-ts-alerting-types'; +import { severityOptions } from '../step_about_rule/data'; +import { useKibana } from '../../../../common/lib/kibana'; +import * as styles from './styles'; +import * as i18n from './translations'; + +interface SeverityOverrideProps { + isDisabled: boolean; + onSeverityMappingChecked: () => void; + onFieldChange: (index: number, severity: Severity, [newField]: DataViewFieldBase[]) => void; + onFieldMatchValueChange: (index: number, severity: Severity, newMatchValue: string) => void; + isMappingChecked: boolean; + dataTestSubj?: string; + idAria?: string; + mapping: SeverityMappingItem[]; + indices: DataViewBase; +} + +export function SeverityOverride({ + isDisabled, + onSeverityMappingChecked, + onFieldChange, + onFieldMatchValueChange, + isMappingChecked, + dataTestSubj = 'severity', + idAria, + mapping, + indices, +}: SeverityOverrideProps) { + const severityMappingLabel = useMemo(() => { + return ( +
    + + + + + {i18n.SEVERITY_MAPPING} + + + + {i18n.SEVERITY_MAPPING_DESCRIPTION} + +
    + ); + }, [onSeverityMappingChecked, isDisabled, isMappingChecked]); + + const describedByIds = useMemo(() => (idAria ? [idAria] : undefined), [idAria]); + + return ( + {i18n.SEVERITY_MAPPING_DETAILS} : '' + } + fullWidth + data-test-subj={`${dataTestSubj}-severityOverride`} + describedByIds={describedByIds} + > + + + {isMappingChecked && ( + + + + + {i18n.SOURCE_FIELD} + + + {i18n.SOURCE_VALUE} + + + + {i18n.DEFAULT_SEVERITY} + + + + + {mapping.map((severityMappingItem, index) => ( + + ))} + + )} + + + ); +} + +interface SeverityMappingRowProps { + severityMappingItem: SeverityMappingItem; + index: number; + indices: DataViewBase; + isDisabled: boolean; + onFieldChange: (index: number, severity: Severity, [newField]: DataViewFieldBase[]) => void; + onFieldMatchValueChange: (index: number, severity: Severity, newMatchValue: string) => void; +} + +function SeverityMappingRow({ + severityMappingItem, + index, + indices, + isDisabled, + onFieldChange, + onFieldMatchValueChange, +}: SeverityMappingRowProps) { + const { services } = useKibana(); + + const handleFieldChange = useCallback( + (newField: DataViewFieldBase[]) => { + onFieldChange(index, severityMappingItem.severity, newField); + }, + [index, severityMappingItem.severity, onFieldChange] + ); + + const handleFieldMatchValueChange = useCallback( + (newMatchValue: string) => { + onFieldMatchValueChange(index, severityMappingItem.severity, newMatchValue); + }, + [index, severityMappingItem.severity, onFieldMatchValueChange] + ); + + return ( + + + + + + + + + + + + + + {severityOptions.find((o) => o.value === severityMappingItem.severity)?.inputDisplay} + + + + ); +} + +const NestedContent: React.FC = ({ children }) => ( +
    {children}
    +); + +const EuiFlexItemComboBoxColumn: React.FC = ({ children }) => ( + {children} +); + +const EuiFlexItemIconColumn: React.FC = ({ children }) => ( + + {children} + +); + +const EuiFlexItemSeverityColumn: React.FC = ({ children }) => ( + + {children} + +); + +/** + * Looks for field metadata (DataViewFieldBase) in existing index pattern. + * If specified field doesn't exist, returns a stub DataViewFieldBase created based on the mapping -- + * because the field might not have been indexed yet, but we still need to display the mapping. + * + * @param mapping Mapping of a specified field name + value to a certain severity value. + * @param pattern Existing index pattern. + */ +const getFieldTypeByMapping = ( + mapping: SeverityMappingItem, + pattern: DataViewBase +): DataViewFieldBase => { + const { field } = mapping; + const [knownFieldType] = pattern.fields.filter(({ name }) => field === name); + return knownFieldType ?? { name: field, type: 'string' }; +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/severity_mapping/styles.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/severity_mapping/styles.ts new file mode 100644 index 000000000000..480a442b250d --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/severity_mapping/styles.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { css } from '@emotion/css'; + +export const nestedContent = css` + margin-left: 24px; +`; + +export const comboBoxColumn = css` + max-width: 376px; +`; + +export const iconColumn = css` + width: 20px; +`; + +export const severityColumn = css` + width: 80px; +`; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_about_rule/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_about_rule/index.tsx index 7666a9ba8aee..ac5c91aa8a25 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_about_rule/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_about_rule/index.tsx @@ -24,7 +24,7 @@ import { AddMitreAttackThreat } from '../mitre'; import type { FieldHook, FormHook } from '../../../../shared_imports'; import { Field, Form, getUseField, UseField } from '../../../../shared_imports'; -import { defaultRiskScoreBySeverity, severityOptions } from './data'; +import { defaultRiskScoreBySeverity } from './data'; import { isUrlInvalid } from '../../../../common/utils/validators'; import { schema as defaultSchema } from './schema'; import * as I18n from './translations'; @@ -32,7 +32,7 @@ import { StepContentWrapper } from '../../../rule_creation/components/step_conte import { MarkdownEditorForm } from '../../../../common/components/markdown_editor/eui_form'; import { SeverityField } from '../severity_mapping'; import { RiskScoreField } from '../risk_score_mapping'; -import { AutocompleteField } from '../autocomplete_field'; +import { EsFieldSelectorField } from '../es_field_selector_field'; import { useFetchIndex } from '../../../../common/containers/source'; import { DEFAULT_INDICATOR_SOURCE_PATH, @@ -176,7 +176,6 @@ const StepAboutRuleComponent: FC = ({ dataTestSubj: 'detectionEngineStepAboutRuleSeverityField', idAria: 'detectionEngineStepAboutRuleSeverityField', isDisabled: isLoading || indexPatternLoading, - options: severityOptions, indices: indexPattern, setRiskScore, }} @@ -376,14 +375,13 @@ const StepAboutRuleComponent: FC = ({ ) : ( )} @@ -391,14 +389,13 @@ const StepAboutRuleComponent: FC = ({ {!!timestampOverride && timestampOverride !== '@timestamp' && ( diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_about_rule/schema.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_about_rule/schema.tsx index 83d79debb757..66c599d0dc72 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_about_rule/schema.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_about_rule/schema.tsx @@ -7,12 +7,22 @@ import { i18n } from '@kbn/i18n'; -import type { FormSchema, ValidationFunc, ERROR_CODE } from '../../../../shared_imports'; +import type { + FormSchema, + ValidationFunc, + ERROR_CODE, + ValidationError, +} from '../../../../shared_imports'; import { FIELD_TYPES, fieldValidators, VALIDATION_TYPES } from '../../../../shared_imports'; -import type { AboutStepRule } from '../../../../detections/pages/detection_engine/rules/types'; +import type { + AboutStepRiskScore, + AboutStepRule, +} from '../../../../detections/pages/detection_engine/rules/types'; import { OptionalFieldLabel } from '../optional_field_label'; import { isUrlInvalid } from '../../../../common/utils/validators'; import * as I18n from './translations'; +import { defaultRiskScoreValidator } from '../../validators/default_risk_score_validator'; +import { maxSignalsValidatorFactory } from '../../validators/max_signals_validator_factory'; const { emptyField } = fieldValidators; @@ -109,6 +119,11 @@ export const schema: FormSchema = { } ), labelAppend: OptionalFieldLabel, + validations: [ + { + validator: maxSignalsValidatorFactory(), + }, + ], }, isAssociatedToEndpointList: { type: FIELD_TYPES.CHECKBOX, @@ -129,6 +144,18 @@ export const schema: FormSchema = { value: {}, mapping: {}, isMappingChecked: {}, + validations: [ + { + validator: ( + ...args: Parameters> + ): ValidationError | undefined => { + const [{ value: fieldValue, path }] = args; + const defaultRiskScore = fieldValue.value; + + return defaultRiskScoreValidator(defaultRiskScore, path); + }, + }, + ], }, references: { label: i18n.translate( 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 cc8f2abda9c4..f1dcfc74e792 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 @@ -202,7 +202,9 @@ const onOpenTimeline = jest.fn(); const COMBO_BOX_TOGGLE_BUTTON_TEST_ID = 'comboBoxToggleListButton'; const VERSION_INPUT_TEST_ID = 'relatedIntegrationVersionDependency'; -describe('StepDefineRule', () => { +// Failing: See https://github.com/elastic/kibana/issues/199648 +// Failing: See https://github.com/elastic/kibana/issues/199700 +describe.skip('StepDefineRule', () => { beforeEach(() => { jest.clearAllMocks(); mockUseRuleFromTimeline.mockReturnValue({ onOpenTimeline, loading: false }); @@ -363,7 +365,7 @@ describe('StepDefineRule', () => { ); }); - it('submits saved early required fields without the "ecs" property', async () => { + it('submits saved earlier required fields', async () => { const initialState = { index: ['test-index'], queryBar: { @@ -388,7 +390,7 @@ describe('StepDefineRule', () => { expect(handleSubmit).toHaveBeenCalledWith( expect.objectContaining({ - requiredFields: [{ name: 'host.name', type: 'string' }], + requiredFields: initialState.requiredFields, }), true ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts index 46dde209804f..7d80ce742325 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts @@ -19,6 +19,7 @@ import type { List, } from '@kbn/securitysolution-io-ts-list-types'; import type { + RiskScoreMappingItem, Threats, ThreatSubtechnique, ThreatTechnique, @@ -57,6 +58,8 @@ import type { RuleCreateProps, AlertSuppression, RequiredFieldInput, + SeverityMapping, + RelatedIntegrationArray, } from '../../../../../common/api/detection_engine/model/rule_schema'; import { stepActionsDefaultValue } from '../../../rule_creation/components/step_rule_actions'; import { DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY } from '../../../../../common/detection_engine/constants'; @@ -407,8 +410,9 @@ export const getStepDataDataSource = ( /** * Strips away form rows that were not filled out by the user */ -const removeEmptyRequiredFields = (requiredFields: RequiredFieldInput[]): RequiredFieldInput[] => - requiredFields.filter((field) => field.name !== '' && field.type !== ''); +export const removeEmptyRequiredFields = ( + requiredFields: RequiredFieldInput[] +): RequiredFieldInput[] => requiredFields.filter((field) => field.name !== '' && field.type !== ''); export const formatDefineStepData = (defineStepData: DefineStepRule): DefineStepRuleJson => { const stepData = getStepDataDataSource(defineStepData); @@ -418,7 +422,9 @@ export const formatDefineStepData = (defineStepData: DefineStepRule): DefineStep const baseFields = { type: ruleType, - related_integrations: defineStepData.relatedIntegrations?.filter((ri) => !isEmpty(ri.package)), + related_integrations: defineStepData.relatedIntegrations + ? filterOutEmptyRelatedIntegrations(defineStepData.relatedIntegrations) + : undefined, ...(timeline.id != null && timeline.title != null && { timeline_id: timeline.id, @@ -624,12 +630,12 @@ export const formatAboutStepData = ( : { field_names: investigationFields }, risk_score: riskScore.value, risk_score_mapping: riskScore.isMappingChecked - ? riskScore.mapping.filter((m) => m.field != null && m.field !== '') + ? filterOutEmptyRiskScoreMappingItems(riskScore.mapping) : [], rule_name_override: ruleNameOverride !== '' ? ruleNameOverride : undefined, severity: severity.value, severity_mapping: severity.isMappingChecked - ? severity.mapping.filter((m) => m.field != null && m.field !== '' && m.value != null) + ? filterOutEmptySeverityMappingItems(severity.mapping) : [], threat: filterEmptyThreats(threat).map((singleThreat) => ({ ...singleThreat, @@ -645,6 +651,15 @@ export const formatAboutStepData = ( return resp; }; +export const filterOutEmptyRiskScoreMappingItems = (riskScoreMapping: RiskScoreMappingItem[]) => + riskScoreMapping.filter((m) => m.field != null && m.field !== ''); + +export const filterOutEmptySeverityMappingItems = (severityMapping: SeverityMapping) => + severityMapping.filter((m) => m.field != null && m.field !== '' && m.value != null); + +export const filterOutEmptyRelatedIntegrations = (relatedIntegrations: RelatedIntegrationArray) => + relatedIntegrations.filter((ri) => !isEmpty(ri.package)); + export const isRuleAction = ( action: AlertingRuleAction | AlertingRuleSystemAction, actionTypeRegistry: ActionTypeRegistryContract diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/default_risk_score_validator.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/default_risk_score_validator.ts new file mode 100644 index 000000000000..6fd7255d4829 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/default_risk_score_validator.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const MIN_RISK_SCORE = 0; +export const MAX_RISK_SCORE = 100; + +export function defaultRiskScoreValidator(defaultRiskScore: unknown, path: string) { + return isDefaultRiskScoreWithinRange(defaultRiskScore) + ? undefined + : { + path, + message: i18n.translate( + 'xpack.securitySolution.ruleManagement.ruleCreation.validation.defaultRiskScoreOutOfRangeValidationError', + { + values: { min: MIN_RISK_SCORE, max: MAX_RISK_SCORE }, + defaultMessage: 'Risk score must be between {min} and {max}.', + } + ), + }; +} + +function isDefaultRiskScoreWithinRange(value: unknown) { + return typeof value === 'number' && value >= MIN_RISK_SCORE && value <= MAX_RISK_SCORE; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/max_signals_validator_factory.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/max_signals_validator_factory.ts new file mode 100644 index 000000000000..b50e0dc4662a --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/max_signals_validator_factory.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import type { ERROR_CODE } from '../../../shared_imports'; +import { fieldValidators, type FormData, type ValidationFunc } from '../../../shared_imports'; + +export const MIN_VALUE = 1; + +export function maxSignalsValidatorFactory(): ValidationFunc { + return fieldValidators.numberGreaterThanField({ + than: MIN_VALUE, + allowEquality: true, + message: i18n.translate( + 'xpack.securitySolution.ruleManagement.ruleCreation.validation.maxSignals.greaterThanError', + { + values: { min: MIN_VALUE }, + defaultMessage: 'Max alerts must be greater than {min}.', + } + ), + }); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.test.tsx index 4ed02135143f..9a9cb5771335 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.test.tsx @@ -32,7 +32,7 @@ jest.mock('../../../../../common/hooks/use_experimental_features', () => { }); const mockTelemetry = { - reportEventLogShowSourceEventDateRange: jest.fn(), + reportEvent: jest.fn(), }; const mockedUseKibana = { @@ -91,6 +91,6 @@ describe('ExecutionLogTable', () => { fireEvent.click(switchButton); - expect(mockTelemetry.reportEventLogShowSourceEventDateRange).toHaveBeenCalled(); + expect(mockTelemetry.reportEvent).toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.tsx index 4546e55522ce..296323213a6d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/execution_log_table/execution_log_table.tsx @@ -85,6 +85,7 @@ import { getSourceEventTimeRangeColumns, } from './execution_log_columns'; import { ExecutionLogSearchBar } from './execution_log_search_bar'; +import { EventLogEventTypes } from '../../../../../common/lib/telemetry'; const EXECUTION_UUID_FIELD_NAME = 'kibana.alert.rule.execution.uuid'; @@ -470,7 +471,7 @@ const ExecutionLogTableComponent: React.FC = ({ (e: EuiSwitchEvent) => { const isVisible = e.target.checked; onShowSourceEventTimeRange(isVisible); - telemetry.reportEventLogShowSourceEventDateRange({ + telemetry.reportEvent(EventLogEventTypes.EventLogShowSourceEventDateRange, { isVisible, }); }, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/rule_backfills_info/stop_backfill.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/rule_backfills_info/stop_backfill.test.tsx index b2cdd83d6f43..faf19fd5dd24 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/rule_backfills_info/stop_backfill.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/rule_backfills_info/stop_backfill.test.tsx @@ -14,6 +14,7 @@ import { TestProviders } from '../../../../common/mock'; import { useKibana } from '../../../../common/lib/kibana'; import * as i18n from '../../translations'; import type { BackfillRow } from '../../types'; +import { ManualRuleRunEventTypes } from '../../../../common/lib/telemetry'; jest.mock('../../../../common/hooks/use_app_toasts'); jest.mock('../../api/hooks/use_delete_backfill'); @@ -25,7 +26,7 @@ const mockUseKibana = useKibana as jest.Mock; describe('StopBackfill', () => { const mockTelemetry = { - reportManualRuleRunCancelJob: jest.fn(), + reportEvent: jest.fn(), }; const addSuccess = jest.fn(); @@ -90,11 +91,14 @@ describe('StopBackfill', () => { fireEvent.click(getByTestId('confirmModalConfirmButton')); await waitFor(() => { - expect(mockTelemetry.reportManualRuleRunCancelJob).toHaveBeenCalledWith({ - totalTasks: backfill.total, - completedTasks: backfill.complete, - errorTasks: backfill.error, - }); + expect(mockTelemetry.reportEvent).toHaveBeenCalledWith( + ManualRuleRunEventTypes.ManualRuleRunCancelJob, + { + totalTasks: backfill.total, + completedTasks: backfill.complete, + errorTasks: backfill.error, + } + ); }); expect(addSuccess).toHaveBeenCalledWith(i18n.BACKFILLS_TABLE_STOP_CONFIRMATION_SUCCESS); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/rule_backfills_info/stop_backfill.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/rule_backfills_info/stop_backfill.tsx index 84acf0b014d6..51d09dc323d8 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/rule_backfills_info/stop_backfill.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/components/rule_backfills_info/stop_backfill.tsx @@ -12,6 +12,7 @@ import { useDeleteBackfill } from '../../api/hooks/use_delete_backfill'; import * as i18n from '../../translations'; import type { BackfillRow } from '../../types'; import { useKibana } from '../../../../common/lib/kibana'; +import { ManualRuleRunEventTypes } from '../../../../common/lib/telemetry'; export const StopBackfill = ({ backfill }: { backfill: BackfillRow }) => { const { telemetry } = useKibana().services; @@ -19,7 +20,7 @@ export const StopBackfill = ({ backfill }: { backfill: BackfillRow }) => { const deleteBackfillMutation = useDeleteBackfill({ onSuccess: () => { closeModal(); - telemetry.reportManualRuleRunCancelJob({ + telemetry.reportEvent(ManualRuleRunEventTypes.ManualRuleRunCancelJob, { totalTasks: backfill.total, completedTasks: backfill.complete, errorTasks: backfill.error, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/logic/use_schedule_rule_run.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/logic/use_schedule_rule_run.test.tsx index 36bdf8a8bf82..ce70bc08bd72 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/logic/use_schedule_rule_run.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/logic/use_schedule_rule_run.test.tsx @@ -11,6 +11,7 @@ import { useKibana } from '../../../common/lib/kibana'; import { useKibana as mockUseKibana } from '../../../common/lib/kibana/__mocks__'; import { TestProviders } from '../../../common/mock'; import { useScheduleRuleRun } from './use_schedule_rule_run'; +import { ManualRuleRunEventTypes } from '../../../common/lib/telemetry'; const mockUseScheduleRuleRunMutation = jest.fn(); @@ -28,7 +29,7 @@ const mockedUseKibana = { services: { ...mockUseKibana().services, telemetry: { - reportManualRuleRunExecute: jest.fn(), + reportEvent: jest.fn(), }, }, }; @@ -61,7 +62,7 @@ describe('When using the `useScheduleRuleRun()` hook', () => { ); }); - it('should call reportManualRuleRunExecute with success status on success', async () => { + it('should call reportEvent with success status on success', async () => { const { result, waitFor } = renderHook(() => useScheduleRuleRun(), { wrapper: TestProviders, }); @@ -77,14 +78,17 @@ describe('When using the `useScheduleRuleRun()` hook', () => { return mockUseScheduleRuleRunMutation.mock.calls.length > 0; }); - expect(mockedUseKibana.services.telemetry.reportManualRuleRunExecute).toHaveBeenCalledWith({ - rangeInMs: timeRange.endDate.diff(timeRange.startDate), - status: 'success', - rulesCount: 1, - }); + expect(mockedUseKibana.services.telemetry.reportEvent).toHaveBeenCalledWith( + ManualRuleRunEventTypes.ManualRuleRunExecute, + { + rangeInMs: timeRange.endDate.diff(timeRange.startDate), + status: 'success', + rulesCount: 1, + } + ); }); - it('should call reportManualRuleRunExecute with error status on failure', async () => { + it('should call reportEvent with error status on failure', async () => { const { result, waitFor } = renderHook(() => useScheduleRuleRun(), { wrapper: TestProviders, }); @@ -100,10 +104,13 @@ describe('When using the `useScheduleRuleRun()` hook', () => { return mockUseScheduleRuleRunMutation.mock.calls.length > 0; }); - expect(mockedUseKibana.services.telemetry.reportManualRuleRunExecute).toHaveBeenCalledWith({ - rangeInMs: timeRange.endDate.diff(timeRange.startDate), - status: 'error', - rulesCount: 1, - }); + expect(mockedUseKibana.services.telemetry.reportEvent).toHaveBeenCalledWith( + ManualRuleRunEventTypes.ManualRuleRunExecute, + { + rangeInMs: timeRange.endDate.diff(timeRange.startDate), + status: 'error', + rulesCount: 1, + } + ); }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/logic/use_schedule_rule_run.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/logic/use_schedule_rule_run.ts index 7599d8685d3c..94f85a30b3ce 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/logic/use_schedule_rule_run.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_gaps/logic/use_schedule_rule_run.ts @@ -12,6 +12,7 @@ import { useScheduleRuleRunMutation } from '../api/hooks/use_schedule_rule_run_m import type { ScheduleBackfillProps } from '../types'; import * as i18n from '../translations'; +import { ManualRuleRunEventTypes } from '../../../common/lib/telemetry'; export function useScheduleRuleRun() { const { mutateAsync } = useScheduleRuleRunMutation(); @@ -22,7 +23,7 @@ export function useScheduleRuleRun() { async (options: ScheduleBackfillProps) => { try { const results = await mutateAsync(options); - telemetry.reportManualRuleRunExecute({ + telemetry.reportEvent(ManualRuleRunEventTypes.ManualRuleRunExecute, { rangeInMs: options.timeRange.endDate.diff(options.timeRange.startDate), status: 'success', rulesCount: options.ruleIds.length, @@ -31,7 +32,7 @@ export function useScheduleRuleRun() { return results; } catch (error) { addError(error, { title: i18n.BACKFILL_SCHEDULE_ERROR_TITLE }); - telemetry.reportManualRuleRunExecute({ + telemetry.reportEvent(ManualRuleRunEventTypes.ManualRuleRunExecute, { rangeInMs: options.timeRange.endDate.diff(options.timeRange.startDate), status: 'error', rulesCount: options.ruleIds.length, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts index 1e2ee1be7a47..aea4b6672659 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts @@ -16,6 +16,7 @@ import type { ActionResult } from '@kbn/actions-plugin/server'; import { convertRulesFilterToKQL } from '../../../../common/detection_engine/rule_management/rule_filtering'; import type { UpgradeSpecificRulesRequest, + PickVersionValues, PerformRuleUpgradeResponseBody, InstallSpecificRulesRequest, PerformRuleInstallationResponseBody, @@ -678,18 +679,9 @@ export const performInstallSpecificRules = async ( }), }); -export const performUpgradeAllRules = async (): Promise => - KibanaServices.get().http.fetch(PERFORM_RULE_UPGRADE_URL, { - method: 'POST', - version: '1', - body: JSON.stringify({ - mode: 'ALL_RULES', - pick_version: 'TARGET', - }), - }); - export const performUpgradeSpecificRules = async ( - rules: UpgradeSpecificRulesRequest['rules'] + rules: UpgradeSpecificRulesRequest['rules'], + pickVersion: PickVersionValues ): Promise => KibanaServices.get().http.fetch(PERFORM_RULE_UPGRADE_URL, { method: 'POST', @@ -697,7 +689,7 @@ export const performUpgradeSpecificRules = async ( body: JSON.stringify({ mode: 'SPECIFIC_RULES', rules, - pick_version: 'TARGET', // Setting fixed 'TARGET' temporarily for Milestone 2 + pick_version: pickVersion, }), }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/prebuilt_rules/use_perform_all_rules_upgrade_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/prebuilt_rules/use_perform_all_rules_upgrade_mutation.ts deleted file mode 100644 index 7e5385bb0c75..000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/prebuilt_rules/use_perform_all_rules_upgrade_mutation.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import type { UseMutationOptions } from '@tanstack/react-query'; -import { useMutation } from '@tanstack/react-query'; -import type { PerformRuleUpgradeResponseBody } from '../../../../../../common/api/detection_engine/prebuilt_rules'; -import { PERFORM_RULE_UPGRADE_URL } from '../../../../../../common/api/detection_engine/prebuilt_rules/urls'; -import { useInvalidateFindRulesQuery } from '../use_find_rules_query'; -import { useInvalidateFetchRuleManagementFiltersQuery } from '../use_fetch_rule_management_filters_query'; -import { useInvalidateFetchRulesSnoozeSettingsQuery } from '../use_fetch_rules_snooze_settings_query'; -import { useInvalidateFetchPrebuiltRulesUpgradeReviewQuery } from './use_fetch_prebuilt_rules_upgrade_review_query'; -import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; -import { performUpgradeAllRules } from '../../api'; -import { useInvalidateFetchCoverageOverviewQuery } from '../use_fetch_coverage_overview_query'; - -export const PERFORM_ALL_RULES_UPGRADE_KEY = ['POST', 'ALL_RULES', PERFORM_RULE_UPGRADE_URL]; - -export const usePerformAllRulesUpgradeMutation = ( - options?: UseMutationOptions -) => { - const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); - const invalidateFetchRulesSnoozeSettings = useInvalidateFetchRulesSnoozeSettingsQuery(); - const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); - const invalidateFetchPrebuiltRulesUpgradeReview = - useInvalidateFetchPrebuiltRulesUpgradeReviewQuery(); - const invalidateRuleStatus = useInvalidateFetchPrebuiltRulesStatusQuery(); - const invalidateFetchCoverageOverviewQuery = useInvalidateFetchCoverageOverviewQuery(); - - return useMutation(() => performUpgradeAllRules(), { - ...options, - mutationKey: PERFORM_ALL_RULES_UPGRADE_KEY, - onSettled: (...args) => { - invalidateFindRulesQuery(); - invalidateFetchRulesSnoozeSettings(); - invalidateFetchRuleManagementFilters(); - - invalidateFetchPrebuiltRulesUpgradeReview(); - invalidateRuleStatus(); - invalidateFetchCoverageOverviewQuery(); - - if (options?.onSettled) { - options.onSettled(...args); - } - }, - }); -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/prebuilt_rules/use_perform_specific_rules_upgrade_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/prebuilt_rules/use_perform_specific_rules_upgrade_mutation.ts index c10b92ea914f..08338ab9a932 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/prebuilt_rules/use_perform_specific_rules_upgrade_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/prebuilt_rules/use_perform_specific_rules_upgrade_mutation.ts @@ -8,6 +8,7 @@ import type { UseMutationOptions } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query'; import type { PerformRuleUpgradeResponseBody, + PickVersionValues, UpgradeSpecificRulesRequest, } from '../../../../../../common/api/detection_engine/prebuilt_rules'; import { PERFORM_RULE_UPGRADE_URL } from '../../../../../../common/api/detection_engine/prebuilt_rules/urls'; @@ -26,6 +27,7 @@ export const PERFORM_SPECIFIC_RULES_UPGRADE_KEY = [ ]; export const usePerformSpecificRulesUpgradeMutation = ( + pickVersion: PickVersionValues, options?: UseMutationOptions< PerformRuleUpgradeResponseBody, Error, @@ -43,7 +45,7 @@ export const usePerformSpecificRulesUpgradeMutation = ( return useMutation( (rulesToUpgrade: UpgradeSpecificRulesRequest['rules']) => { - return performUpgradeSpecificRules(rulesToUpgrade); + return performUpgradeSpecificRules(rulesToUpgrade, pickVersion); }, { ...options, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/customized_prebuilt_rule_badge.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/customized_prebuilt_rule_badge.tsx index 56a559a91794..e4b00196f476 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/customized_prebuilt_rule_badge.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/customized_prebuilt_rule_badge.tsx @@ -10,7 +10,7 @@ import { EuiBadge } from '@elastic/eui'; import * as i18n from './translations'; import { isCustomizedPrebuiltRule } from '../../../../../common/api/detection_engine'; import type { RuleResponse } from '../../../../../common/api/detection_engine'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; +import { useIsPrebuiltRulesCustomizationEnabled } from '../../hooks/use_is_prebuilt_rules_customization_enabled'; interface CustomizedPrebuiltRuleBadgeProps { rule: RuleResponse | null; @@ -19,9 +19,7 @@ interface CustomizedPrebuiltRuleBadgeProps { export const CustomizedPrebuiltRuleBadge: React.FC = ({ rule, }) => { - const isPrebuiltRulesCustomizationEnabled = useIsExperimentalFeatureEnabled( - 'prebuiltRulesCustomizationEnabled' - ); + const isPrebuiltRulesCustomizationEnabled = useIsPrebuiltRulesCustomizationEnabled(); if (!isPrebuiltRulesCustomizationEnabled) { return null; @@ -31,5 +29,5 @@ export const CustomizedPrebuiltRuleBadge: React.FC{i18n.CUSTOMIZED_PREBUILT_RULE_LABEL}; + return {i18n.MODIFIED_PREBUILT_RULE_LABEL}; }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx index fefd35fcfaf6..3f10ce014d82 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/common_rule_field_edit.tsx @@ -7,16 +7,247 @@ import React from 'react'; import { RuleFieldEditFormWrapper } from './fields/rule_field_edit_form_wrapper'; -import { NameEdit, nameSchema } from './fields/name'; import type { UpgradeableCommonFields } from '../../../../model/prebuilt_rule_upgrade/fields'; +import { + BuildingBlockEdit, + buildingBlockSchema, + buildingBlockDeserializer, + buildingBlockSerializer, +} from './fields/building_block'; +import { DescriptionEdit, descriptionSchema } from './fields/description'; +import { + FalsePositivesEdit, + falsePositivesSchema, + falsePositivesSerializer, + falsePositivesDeserializer, +} from './fields/false_positives'; +import { + InvestigationFieldsEdit, + investigationFieldsSchema, + investigationFieldsDeserializer, + investigationFieldsSerializer, +} from './fields/investigation_fields'; +import { + MaxSignalsEdit, + maxSignalsDeserializer, + maxSignalsSchema, + maxSignalsSerializer, +} from './fields/max_signals'; +import { NameEdit, nameSchema } from './fields/name'; +import { NoteEdit, noteSchema } from './fields/note'; +import { ReferencesEdit, referencesSchema, referencesSerializer } from './fields/references'; +import { + RelatedIntegrationsEdit, + relatedIntegrationsSchema, + relatedIntegrationsDeserializer, + relatedIntegrationsSerializer, +} from './fields/related_integrations'; +import { + RequiredFieldsEdit, + requiredFieldsSchema, + requiredFieldsDeserializer, + requiredFieldsSerializer, +} from './fields/required_fields'; +import { + RiskScoreEdit, + riskScoreDeserializer, + riskScoreSchema, + riskScoreSerializer, +} from './fields/risk_score'; +import { + RiskScoreMappingEdit, + riskScoreMappingDeserializer, + riskScoreMappingSerializer, +} from './fields/risk_score_mapping'; +import { + RuleNameOverrideEdit, + ruleNameOverrideDeserializer, + ruleNameOverrideSerializer, + ruleNameOverrideSchema, +} from './fields/rule_name_override'; +import { + RuleScheduleEdit, + ruleScheduleSchema, + ruleScheduleDeserializer, + ruleScheduleSerializer, +} from './fields/rule_schedule'; +import { SetupEdit, setupSchema } from './fields/setup'; +import { SeverityEdit } from './fields/severity'; +import { + SeverityMappingEdit, + severityMappingDeserializer, + severityMappingSerializer, +} from './fields/severity_mapping'; +import { TagsEdit, tagsSchema } from './fields/tags'; +import { ThreatEdit, threatSchema, threatSerializer } from './fields/threat'; +import { + TimelineTemplateEdit, + timelineTemplateDeserializer, + timelineTemplateSchema, + timelineTemplateSerializer, +} from './fields/timeline_template'; +import { + TimestampOverrideEdit, + timestampOverrideDeserializer, + timestampOverrideSerializer, + timestampOverrideSchema, +} from './fields/timestamp_override'; + interface CommonRuleFieldEditProps { fieldName: UpgradeableCommonFields; } +/* eslint-disable-next-line complexity */ export function CommonRuleFieldEdit({ fieldName }: CommonRuleFieldEditProps) { switch (fieldName) { + case 'building_block': + return ( + + ); + case 'description': + return ( + + ); + case 'false_positives': + return ( + + ); + case 'investigation_fields': + return ( + + ); + case 'max_signals': + return ( + + ); case 'name': return ; + case 'note': + return ; + case 'references': + return ( + + ); + case 'related_integrations': + return ( + + ); + case 'required_fields': + return ( + + ); + case 'risk_score': + return ( + + ); + case 'risk_score_mapping': + return ( + + ); + case 'rule_name_override': + return ( + + ); + case 'rule_schedule': + return ( + + ); + case 'setup': + return ; + case 'severity': + return ; + case 'severity_mapping': + return ( + + ); + case 'tags': + return ; + case 'timeline_template': + return ( + + ); + case 'timestamp_override': + return ( + + ); + case 'threat': + return ( + + ); default: return null; // Will be replaced with `assertUnreachable(fieldName)` once all fields are implemented } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/building_block.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/building_block.tsx new file mode 100644 index 000000000000..3b21ff76f07a --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/building_block.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FormSchema, FormData } from '../../../../../../../shared_imports'; +import { Field, UseField } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema'; +import type { BuildingBlockObject } from '../../../../../../../../common/api/detection_engine'; + +export const buildingBlockSchema = { isBuildingBlock: schema.isBuildingBlock } as FormSchema<{ + isBuildingBlock: boolean; +}>; + +export function BuildingBlockEdit(): JSX.Element { + return ; +} + +export function buildingBlockDeserializer(defaultValue: FormData) { + return { + isBuildingBlock: defaultValue.building_block, + }; +} + +export function buildingBlockSerializer(formData: FormData): { + building_block: BuildingBlockObject | undefined; +} { + return { building_block: formData.isBuildingBlock ? { type: 'default' } : undefined }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/description.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/description.tsx new file mode 100644 index 000000000000..c2d279c0d72e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/description.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FormSchema } from '../../../../../../../shared_imports'; +import { Field, UseField } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema'; +import type { RuleDescription } from '../../../../../../../../common/api/detection_engine'; + +export const descriptionSchema = { description: schema.description } as FormSchema<{ + description: RuleDescription; +}>; + +const componentProps = { + euiFieldProps: { + fullWidth: true, + compressed: true, + }, +}; + +export function DescriptionEdit(): JSX.Element { + return ; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/false_positives.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/false_positives.tsx new file mode 100644 index 000000000000..ddb23732b187 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/false_positives.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { isEmpty } from 'lodash'; +import * as i18n from '../../../../../../rule_creation_ui/components/step_about_rule/translations'; +import type { FormSchema, FormData } from '../../../../../../../shared_imports'; +import { UseField } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema'; +import type { RuleFalsePositiveArray } from '../../../../../../../../common/api/detection_engine'; +import { AddItem } from '../../../../../../rule_creation_ui/components/add_item_form'; + +export const falsePositivesSchema = { falsePositives: schema.falsePositives } as FormSchema<{ + falsePositives: RuleFalsePositiveArray; +}>; + +const componentProps = { + addText: i18n.ADD_FALSE_POSITIVE, +}; + +export function FalsePositivesEdit(): JSX.Element { + return ; +} + +export function falsePositivesDeserializer(defaultValue: FormData) { + return { + falsePositives: defaultValue.false_positives, + }; +} + +export function falsePositivesSerializer(formData: FormData): { + false_positives: RuleFalsePositiveArray; +} { + const falsePositives: RuleFalsePositiveArray = formData.falsePositives; + + return { + /* Remove empty items from the falsePositives array */ + false_positives: falsePositives.filter((item) => !isEmpty(item)), + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/investigation_fields.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/investigation_fields.tsx new file mode 100644 index 000000000000..971174f45539 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/investigation_fields.tsx @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FormSchema, FormData } from '../../../../../../../shared_imports'; +import { UseField } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema'; +import type { + DiffableRule, + InvestigationFields, + RuleFalsePositiveArray, +} from '../../../../../../../../common/api/detection_engine'; +import { MultiSelectFieldsAutocomplete } from '../../../../../../rule_creation_ui/components/multi_select_fields'; +import { useAllEsqlRuleFields } from '../../../../../../rule_creation_ui/hooks'; +import { useDefaultIndexPattern } from '../../../../../hooks/use_default_index_pattern'; +import { useRuleIndexPattern } from '../../../../../../rule_creation_ui/pages/form'; +import { getUseRuleIndexPatternParameters } from '../utils'; + +export const investigationFieldsSchema = { + investigationFields: schema.investigationFields, +} as FormSchema<{ + investigationFields: RuleFalsePositiveArray; +}>; + +interface InvestigationFieldsEditProps { + finalDiffableRule: DiffableRule; +} + +export function InvestigationFieldsEdit({ + finalDiffableRule, +}: InvestigationFieldsEditProps): JSX.Element { + const { type } = finalDiffableRule; + + const defaultIndexPattern = useDefaultIndexPattern(); + const indexPatternParameters = getUseRuleIndexPatternParameters( + finalDiffableRule, + defaultIndexPattern + ); + const { indexPattern, isIndexPatternLoading } = useRuleIndexPattern(indexPatternParameters); + + const { fields: investigationFields, isLoading: isInvestigationFieldsLoading } = + useAllEsqlRuleFields({ + esqlQuery: type === 'esql' ? finalDiffableRule.esql_query.query : undefined, + indexPatternsFields: indexPattern.fields, + }); + + return ( + + ); +} + +export function investigationFieldsDeserializer(defaultValue: FormData) { + return { + investigationFields: defaultValue.investigation_fields?.field_names ?? [], + }; +} + +export function investigationFieldsSerializer(formData: FormData): { + investigation_fields: InvestigationFields | undefined; +} { + const hasInvestigationFields = formData.investigationFields.length > 0; + + return { + investigation_fields: hasInvestigationFields + ? { + field_names: formData.investigationFields, + } + : undefined, + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/max_signals.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/max_signals.tsx new file mode 100644 index 000000000000..dd7774eaa5ac --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/max_signals.tsx @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FormSchema, FormData } from '../../../../../../../shared_imports'; +import { UseField } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema'; +import type { MaxSignals as MaxSignalsType } from '../../../../../../../../common/api/detection_engine'; +import { DEFAULT_MAX_SIGNALS } from '../../../../../../../../common/constants'; +import { MaxSignals } from '../../../../../../rule_creation_ui/components/max_signals'; + +export const maxSignalsSchema = { maxSignals: schema.maxSignals } as FormSchema<{ + maxSignals: boolean; +}>; + +const componentProps = { + placeholder: DEFAULT_MAX_SIGNALS, +}; + +export function MaxSignalsEdit(): JSX.Element { + return ; +} + +export function maxSignalsDeserializer(defaultValue: FormData) { + return { + maxSignals: defaultValue.max_signals, + }; +} + +export function maxSignalsSerializer(formData: FormData): { + max_signals: MaxSignalsType; +} { + return { + max_signals: Number.isSafeInteger(formData.maxSignals) + ? formData.maxSignals + : DEFAULT_MAX_SIGNALS, + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/name.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/name.tsx index 10ae6cffbe50..d602da90f34b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/name.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/name.tsx @@ -13,16 +13,12 @@ import type { RuleName } from '../../../../../../../../common/api/detection_engi export const nameSchema = { name: schema.name } as FormSchema<{ name: RuleName }>; +const componentProps = { + euiFieldProps: { + fullWidth: true, + }, +}; + export function NameEdit(): JSX.Element { - return ( - - ); + return ; } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/note.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/note.tsx new file mode 100644 index 000000000000..3a560fd28f27 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/note.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FormSchema } from '../../../../../../../shared_imports'; +import { UseField } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema'; +import type { InvestigationGuide } from '../../../../../../../../common/api/detection_engine'; +import * as i18n from '../../../../../../rule_creation_ui/components/step_about_rule/translations'; +import { MarkdownEditorForm } from '../../../../../../../common/components/markdown_editor'; + +export const noteSchema = { note: schema.note } as FormSchema<{ + note: InvestigationGuide; +}>; + +const componentProps = { + placeholder: i18n.ADD_RULE_NOTE_HELP_TEXT, +}; + +export function NoteEdit(): JSX.Element { + return ; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/references.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/references.tsx new file mode 100644 index 000000000000..afa4fba09d89 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/references.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 { compact } from 'lodash'; +import * as i18n from '../../../../../../rule_creation_ui/components/step_about_rule/translations'; +import type { FormSchema, FormData } from '../../../../../../../shared_imports'; +import { UseField } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema'; +import type { RuleReferenceArray } from '../../../../../../../../common/api/detection_engine'; +import { AddItem } from '../../../../../../rule_creation_ui/components/add_item_form'; +import { isUrlInvalid } from '../../../../../../../common/utils/validators'; + +export const referencesSchema = { references: schema.references } as FormSchema<{ + references: RuleReferenceArray; +}>; + +const componentProps = { + addText: i18n.ADD_REFERENCE, + validate: isUrlInvalid, +}; + +export function ReferencesEdit(): JSX.Element { + return ; +} + +export function referencesSerializer(formData: FormData): { + references: RuleReferenceArray; +} { + return { + /* Remove empty items from the references array */ + references: compact(formData.references), + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/related_integrations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/related_integrations.tsx new file mode 100644 index 000000000000..443f0b4bb775 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/related_integrations.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FormSchema, FormData } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_define_rule/schema'; +import { RelatedIntegrations } from '../../../../../../rule_creation/components/related_integrations'; +import type { RelatedIntegrationArray } from '../../../../../../../../common/api/detection_engine'; +import { filterOutEmptyRelatedIntegrations } from '../../../../../../rule_creation_ui/pages/rule_creation/helpers'; + +export const relatedIntegrationsSchema = { + relatedIntegrations: schema.relatedIntegrations, +} as FormSchema<{ + relatedIntegrations: RelatedIntegrationArray; +}>; + +export function RelatedIntegrationsEdit(): JSX.Element { + return ; +} + +export function relatedIntegrationsDeserializer(defaultValue: FormData) { + return { + relatedIntegrations: defaultValue.related_integrations, + }; +} + +export function relatedIntegrationsSerializer(formData: FormData): { + related_integrations: RelatedIntegrationArray; +} { + const relatedIntegrations = (formData.relatedIntegrations ?? []) as RelatedIntegrationArray; + + return { + related_integrations: filterOutEmptyRelatedIntegrations(relatedIntegrations), + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/required_fields.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/required_fields.tsx new file mode 100644 index 000000000000..3e6809e35a4f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/required_fields.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 type { FormSchema, FormData } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_define_rule/schema'; +import type { + DiffableRule, + RequiredFieldInput, +} from '../../../../../../../../common/api/detection_engine'; +import { RequiredFields } from '../../../../../../rule_creation/components/required_fields'; +import { useDefaultIndexPattern } from '../../../../../hooks/use_default_index_pattern'; +import { getUseRuleIndexPatternParameters } from '../utils'; +import { useRuleIndexPattern } from '../../../../../../rule_creation_ui/pages/form'; +import { removeEmptyRequiredFields } from '../../../../../../rule_creation_ui/pages/rule_creation/helpers'; + +export const requiredFieldsSchema = { + requiredFields: schema.requiredFields, +} as FormSchema<{ + requiredFields: RequiredFieldInput[]; +}>; + +interface RequiredFieldsEditProps { + finalDiffableRule: DiffableRule; +} + +export function RequiredFieldsEdit({ finalDiffableRule }: RequiredFieldsEditProps): JSX.Element { + const defaultIndexPattern = useDefaultIndexPattern(); + const indexPatternParameters = getUseRuleIndexPatternParameters( + finalDiffableRule, + defaultIndexPattern + ); + const { indexPattern, isIndexPatternLoading } = useRuleIndexPattern(indexPatternParameters); + + return ( + + ); +} + +export function requiredFieldsDeserializer(defaultValue: FormData) { + return { + requiredFields: defaultValue.required_fields, + }; +} + +export function requiredFieldsSerializer(formData: FormData): { + required_fields: RequiredFieldInput[]; +} { + const requiredFields = (formData.requiredFields ?? []) as RequiredFieldInput[]; + return { + required_fields: removeEmptyRequiredFields(requiredFields), + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/risk_score.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/risk_score.tsx new file mode 100644 index 000000000000..757521370605 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/risk_score.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + type FormData, + type FieldHook, + UseField, + getFieldValidityAndErrorMessage, +} from '../../../../../../../shared_imports'; +import type { RiskScore } from '../../../../../../../../common/api/detection_engine'; +import { DefaultRiskScore } from '../../../../../../rule_creation_ui/components/risk_score_mapping/default_risk_score'; +import { defaultRiskScoreValidator } from '../../../../../../rule_creation_ui/validators/default_risk_score_validator'; + +export const riskScoreSchema = { + riskScore: { + validations: [ + { + validator: ({ path, value }: { path: string; value: unknown }) => + defaultRiskScoreValidator(value, path), + }, + ], + }, +}; + +export function RiskScoreEdit(): JSX.Element { + return ; +} + +interface RiskScoreEditFieldProps { + field: FieldHook; +} + +function RiskScoreEditField({ field }: RiskScoreEditFieldProps) { + const { value, setValue } = field; + const errorMessage = getFieldValidityAndErrorMessage(field).errorMessage ?? undefined; + + return ; +} + +export function riskScoreDeserializer(defaultValue: FormData) { + return { + riskScore: defaultValue.risk_score, + }; +} + +export function riskScoreSerializer(formData: FormData): { + risk_score: RiskScore; +} { + return { + risk_score: formData.riskScore, + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/risk_score_mapping.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/risk_score_mapping.tsx new file mode 100644 index 000000000000..a1e5e3f80630 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/risk_score_mapping.tsx @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback } from 'react'; +import type { DataViewFieldBase } from '@kbn/es-query'; +import { type FormData, type FieldHook, UseField } from '../../../../../../../shared_imports'; +import type { + DiffableRule, + RiskScoreMapping, +} from '../../../../../../../../common/api/detection_engine'; +import { RiskScoreOverride } from '../../../../../../rule_creation_ui/components/risk_score_mapping/risk_score_override'; +import { useDefaultIndexPattern } from '../../../../../hooks/use_default_index_pattern'; +import { getUseRuleIndexPatternParameters } from '../utils'; +import { useRuleIndexPattern } from '../../../../../../rule_creation_ui/pages/form'; +import { filterOutEmptyRiskScoreMappingItems } from '../../../../../../rule_creation_ui/pages/rule_creation/helpers'; + +interface RiskScoreMappingEditProps { + finalDiffableRule: DiffableRule; +} + +export function RiskScoreMappingEdit({ finalDiffableRule }: RiskScoreMappingEditProps) { + return ( + + ); +} + +interface RiskScoreMappingFieldProps { + field: FieldHook<{ isMappingChecked: boolean; mapping: RiskScoreMapping }>; + finalDiffableRule: DiffableRule; +} + +function RiskScoreMappingField({ field, finalDiffableRule }: RiskScoreMappingFieldProps) { + const defaultIndexPattern = useDefaultIndexPattern(); + const indexPatternParameters = getUseRuleIndexPatternParameters( + finalDiffableRule, + defaultIndexPattern + ); + const { indexPattern, isIndexPatternLoading } = useRuleIndexPattern(indexPatternParameters); + + const { value, setValue } = field; + + const handleToggleMappingChecked = useCallback(() => { + setValue((prevValue) => ({ + ...prevValue, + isMappingChecked: !prevValue.isMappingChecked, + })); + }, [setValue]); + + const handleMappingChange = useCallback( + ([newField]: DataViewFieldBase[]): void => { + const mapping = [ + { + field: newField?.name ?? '', + operator: 'equals' as const, + value: '', + }, + ]; + + setValue((prevValue) => ({ + ...prevValue, + mapping, + })); + }, + [setValue] + ); + + return ( + + ); +} + +export function riskScoreMappingDeserializer(defaultValue: FormData) { + return { + riskScoreMapping: { + isMappingChecked: defaultValue.risk_score_mapping.length > 0, + mapping: defaultValue.risk_score_mapping, + }, + }; +} + +export function riskScoreMappingSerializer(formData: FormData): { + risk_score_mapping: RiskScoreMapping; +} { + return { + risk_score_mapping: formData.riskScoreMapping.isMappingChecked + ? filterOutEmptyRiskScoreMappingItems(formData.riskScoreMapping.mapping) + : [], + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_form_wrapper.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_form_wrapper.tsx index 26a2574489b1..1b45bea28880 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_form_wrapper.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_field_edit_form_wrapper.tsx @@ -27,13 +27,13 @@ export type FieldDeserializerFn = ( interface RuleFieldEditFormWrapperProps { component: RuleFieldEditComponent; - ruleFieldFormSchema: FormSchema; + ruleFieldFormSchema?: FormSchema; deserializer?: FieldDeserializerFn; serializer?: (formData: FormData) => FormData; } /** - * FieldFormWrapper component manages form state and renders "Save" and "Cancel" buttons. + * RuleFieldEditFormWrapper component manages form state and renders "Save" and "Cancel" buttons. * * @param {Object} props - Component props. * @param {React.ComponentType} props.component - Field component to be wrapped. diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_name_override.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_name_override.tsx new file mode 100644 index 000000000000..d13395643650 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_name_override.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import type { FormSchema, FormData } from '../../../../../../../shared_imports'; +import { UseField } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema'; +import type { + DiffableRule, + RuleNameOverrideObject, +} from '../../../../../../../../common/api/detection_engine'; +import { EsFieldSelectorField } from '../../../../../../rule_creation_ui/components/es_field_selector_field'; +import { useRuleIndexPattern } from '../../../../../../rule_creation_ui/pages/form'; +import { getUseRuleIndexPatternParameters } from '../utils'; +import { useDefaultIndexPattern } from '../../../../../hooks/use_default_index_pattern'; + +export const ruleNameOverrideSchema = { ruleNameOverride: schema.ruleNameOverride } as FormSchema<{ + ruleNameOverride: string; +}>; + +interface RuleNameOverrideEditProps { + finalDiffableRule: DiffableRule; +} + +export function RuleNameOverrideEdit({ + finalDiffableRule, +}: RuleNameOverrideEditProps): JSX.Element { + const defaultIndexPattern = useDefaultIndexPattern(); + const indexPatternParameters = getUseRuleIndexPatternParameters( + finalDiffableRule, + defaultIndexPattern + ); + const { indexPattern, isIndexPatternLoading } = useRuleIndexPattern(indexPatternParameters); + + const componentProps = useMemo( + () => ({ + fieldType: 'string', + indices: indexPattern, + isDisabled: isIndexPatternLoading, + }), + [indexPattern, isIndexPatternLoading] + ); + + return ( + + ); +} + +export function ruleNameOverrideDeserializer(defaultValue: FormData) { + return { + ruleNameOverride: defaultValue.rule_name_override?.field_name ?? '', + }; +} + +export function ruleNameOverrideSerializer(formData: FormData): { + rule_name_override: RuleNameOverrideObject | undefined; +} { + return { + rule_name_override: formData.ruleNameOverride + ? { field_name: formData.ruleNameOverride } + : undefined, + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_schedule.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_schedule.tsx new file mode 100644 index 000000000000..12e7bbea9a20 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/rule_schedule.tsx @@ -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 React from 'react'; +import { parseDuration } from '@kbn/alerting-plugin/common'; +import { type FormSchema, type FormData, UseField } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_schedule_rule/schema'; +import type { RuleSchedule } from '../../../../../../../../common/api/detection_engine'; +import { ScheduleItem } from '../../../../../../rule_creation/components/schedule_item_form'; +import { secondsToDurationString } from '../../../../../../../detections/pages/detection_engine/rules/helpers'; + +export const ruleScheduleSchema = { + interval: schema.interval, + from: schema.from, +} as FormSchema<{ + interval: string; + from: string; +}>; + +const componentProps = { + minimumValue: 1, +}; + +export function RuleScheduleEdit(): JSX.Element { + return ( + <> + + + + ); +} + +export function ruleScheduleDeserializer(defaultValue: FormData) { + const lookbackSeconds = parseDuration(defaultValue.rule_schedule.lookback) / 1000; + const lookbackHumanized = secondsToDurationString(lookbackSeconds); + + return { + interval: defaultValue.rule_schedule.interval, + from: lookbackHumanized, + }; +} + +export function ruleScheduleSerializer(formData: FormData): { + rule_schedule: RuleSchedule; +} { + return { + rule_schedule: { + interval: formData.interval, + lookback: formData.from, + }, + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/setup.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/setup.tsx new file mode 100644 index 000000000000..8304641d1b16 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/setup.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FormSchema } from '../../../../../../../shared_imports'; +import { UseField } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema'; +import type { SetupGuide } from '../../../../../../../../common/api/detection_engine'; +import * as i18n from '../../../../../../rule_creation_ui/components/step_about_rule/translations'; +import { MarkdownEditorForm } from '../../../../../../../common/components/markdown_editor'; + +export const setupSchema = { setup: schema.setup } as FormSchema<{ + setup: SetupGuide; +}>; + +const componentProps = { + placeholder: i18n.ADD_RULE_SETUP_HELP_TEXT, + includePlugins: false, +}; + +export function SetupEdit(): JSX.Element { + return ; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/severity.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/severity.tsx new file mode 100644 index 000000000000..1a6bf03ea67f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/severity.tsx @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { type FieldHook, UseField } from '../../../../../../../shared_imports'; +import type { Severity } from '../../../../../../../../common/api/detection_engine'; +import { DefaultSeverity } from '../../../../../../rule_creation_ui/components/severity_mapping/default_severity'; + +export function SeverityEdit(): JSX.Element { + return ; +} + +interface SeverityEditFieldProps { + field: FieldHook; +} + +function SeverityEditField({ field }: SeverityEditFieldProps) { + const { value, setValue } = field; + + return ; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/severity_mapping.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/severity_mapping.tsx new file mode 100644 index 000000000000..d4206549bfa1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/severity_mapping.tsx @@ -0,0 +1,149 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback } from 'react'; +import type { DataViewFieldBase } from '@kbn/es-query'; +import { type FieldHook, type FormData, UseField } from '../../../../../../../shared_imports'; +import type { + DiffableRule, + Severity, + SeverityMapping, +} from '../../../../../../../../common/api/detection_engine'; +import { SeverityOverride } from '../../../../../../rule_creation_ui/components/severity_mapping/severity_override'; +import { useDefaultIndexPattern } from '../../../../../hooks/use_default_index_pattern'; +import { getUseRuleIndexPatternParameters } from '../utils'; +import { useRuleIndexPattern } from '../../../../../../rule_creation_ui/pages/form'; +import { fillEmptySeverityMappings } from '../../../../../../../detections/pages/detection_engine/rules/helpers'; +import { filterOutEmptySeverityMappingItems } from '../../../../../../rule_creation_ui/pages/rule_creation/helpers'; + +interface SeverityMappingEditProps { + finalDiffableRule: DiffableRule; +} + +export function SeverityMappingEdit({ finalDiffableRule }: SeverityMappingEditProps): JSX.Element { + return ( + + ); +} + +interface SeverityMappingFieldProps { + field: FieldHook<{ + isMappingChecked: boolean; + mapping: SeverityMapping; + }>; + finalDiffableRule: DiffableRule; +} + +function SeverityMappingField({ field, finalDiffableRule }: SeverityMappingFieldProps) { + const defaultIndexPattern = useDefaultIndexPattern(); + const indexPatternParameters = getUseRuleIndexPatternParameters( + finalDiffableRule, + defaultIndexPattern + ); + const { indexPattern, isIndexPatternLoading } = useRuleIndexPattern(indexPatternParameters); + + const { value, setValue } = field; + + const handleFieldChange = useCallback( + (index: number, severity: Severity, [newField]: DataViewFieldBase[]): void => { + setValue((prevValue) => { + const newMappingItem: SeverityMapping = [ + { + ...prevValue.mapping[index], + field: newField?.name ?? '', + value: newField != null ? prevValue.mapping[index].value : '', + operator: 'equals', + severity, + }, + ]; + + return { + ...prevValue, + mapping: [ + ...prevValue.mapping.slice(0, index), + ...newMappingItem, + ...prevValue.mapping.slice(index + 1), + ], + }; + }); + }, + [setValue] + ); + + const handleFieldMatchValueChange = useCallback( + (index: number, severity: Severity, newMatchValue: string): void => { + setValue((prevValue) => { + const newMappingItem: SeverityMapping = [ + { + ...prevValue.mapping[index], + field: prevValue.mapping[index].field, + value: + prevValue.mapping[index].field != null && prevValue.mapping[index].field !== '' + ? newMatchValue + : '', + operator: 'equals', + severity, + }, + ]; + + return { + ...prevValue, + mapping: [ + ...prevValue.mapping.slice(0, index), + ...newMappingItem, + ...prevValue.mapping.slice(index + 1), + ], + }; + }); + }, + [setValue] + ); + + const handleSeverityMappingChecked = useCallback(() => { + setValue((prevValue) => ({ + ...prevValue, + isMappingChecked: !prevValue.isMappingChecked, + })); + }, [setValue]); + + return ( + + ); +} + +export function severityMappingDeserializer(defaultValue: FormData) { + return { + severityMapping: { + isMappingChecked: defaultValue.severity_mapping.length > 0, + mapping: fillEmptySeverityMappings(defaultValue.severity_mapping as SeverityMapping), + }, + }; +} + +export function severityMappingSerializer(formData: FormData): { + severity_mapping: SeverityMapping; +} { + return { + severity_mapping: formData.severityMapping.isMappingChecked + ? filterOutEmptySeverityMappingItems(formData.severityMapping.mapping) + : [], + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/tags.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/tags.tsx new file mode 100644 index 000000000000..063b7f4f48b8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/tags.tsx @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FormSchema } from '../../../../../../../shared_imports'; +import { Field, UseField } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema'; +import type { RuleTagArray } from '../../../../../../../../common/api/detection_engine'; + +export const tagsSchema = { tags: schema.tags } as FormSchema<{ name: RuleTagArray }>; + +const componentProps = { + euiFieldProps: { + fullWidth: true, + placeholder: '', + }, +}; + +export function TagsEdit(): JSX.Element { + return ; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/threat.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/threat.tsx new file mode 100644 index 000000000000..fbc0541ff50f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/threat.tsx @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { type FormSchema, type FormData, UseField } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema'; +import type { ThreatArray } from '../../../../../../../../common/api/detection_engine'; +import { AddMitreAttackThreat } from '../../../../../../rule_creation_ui/components/mitre'; +import { filterEmptyThreats } from '../../../../../../rule_creation_ui/pages/rule_creation/helpers'; + +export const threatSchema = { threat: schema.threat } as FormSchema<{ threat: ThreatArray }>; + +export function ThreatEdit(): JSX.Element { + return ; +} + +export function threatSerializer(formData: FormData): { + threat: ThreatArray; +} { + return { + threat: filterEmptyThreats(formData.threat).map((singleThreat) => ({ + ...singleThreat, + framework: 'MITRE ATT&CK', + })), + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/timeline_template.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/timeline_template.tsx new file mode 100644 index 000000000000..1f7ef2eaf05b --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/timeline_template.tsx @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FormSchema, FormData } from '../../../../../../../shared_imports'; +import { UseField } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_define_rule/schema'; +import type { TimelineTemplateReference } from '../../../../../../../../common/api/detection_engine'; +import { + PickTimeline, + type FieldValueTimeline, +} from '../../../../../../rule_creation/components/pick_timeline'; + +export const timelineTemplateSchema = { timeline: schema.timeline } as FormSchema<{ + timeline: FieldValueTimeline; +}>; + +export function TimelineTemplateEdit(): JSX.Element { + return ; +} + +export function timelineTemplateDeserializer(defaultValue: FormData) { + return { + timeline: { + id: defaultValue.timeline_template?.timeline_id ?? null, + title: defaultValue.timeline_template?.timeline_title ?? null, + }, + }; +} + +export function timelineTemplateSerializer(formData: FormData): { + timeline_template: TimelineTemplateReference | undefined; +} { + if (!formData.timeline.id) { + return { timeline_template: undefined }; + } + + return { + timeline_template: { + timeline_id: formData.timeline.id, + timeline_title: formData.timeline.title, + }, + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/timestamp_override.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/timestamp_override.tsx new file mode 100644 index 000000000000..a57d538fab47 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/timestamp_override.tsx @@ -0,0 +1,95 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import type { FormSchema, FormData } from '../../../../../../../shared_imports'; +import { Field, UseField, useFormData } from '../../../../../../../shared_imports'; +import { schema } from '../../../../../../rule_creation_ui/components/step_about_rule/schema'; +import { EsFieldSelectorField } from '../../../../../../rule_creation_ui/components/es_field_selector_field'; +import { useDefaultIndexPattern } from '../../../../../hooks/use_default_index_pattern'; +import { getUseRuleIndexPatternParameters } from '../utils'; +import { useRuleIndexPattern } from '../../../../../../rule_creation_ui/pages/form'; +import type { + DiffableRule, + TimestampOverrideObject, +} from '../../../../../../../../common/api/detection_engine'; + +export const timestampOverrideSchema = { + timestampOverride: schema.timestampOverride, + timestampOverrideFallbackDisabled: schema.timestampOverrideFallbackDisabled, +} as FormSchema<{ + timestampOverride: string; + timestampOverrideFallbackDisabled: boolean | undefined; +}>; + +interface TimestampOverrideEditProps { + finalDiffableRule: DiffableRule; +} + +export function TimestampOverrideEdit({ + finalDiffableRule, +}: TimestampOverrideEditProps): JSX.Element { + const defaultIndexPattern = useDefaultIndexPattern(); + const indexPatternParameters = getUseRuleIndexPatternParameters( + finalDiffableRule, + defaultIndexPattern + ); + const { indexPattern, isIndexPatternLoading } = useRuleIndexPattern(indexPatternParameters); + + const componentProps = useMemo( + () => ({ + fieldType: 'date', + indices: indexPattern, + isDisabled: isIndexPatternLoading, + }), + [indexPattern, isIndexPatternLoading] + ); + + return ( + <> + + + + ); +} + +function TimestampFallbackDisabled() { + const [formData] = useFormData(); + const { timestampOverride } = formData; + + if (timestampOverride && timestampOverride !== '@timestamp') { + return ; + } + + return null; +} + +export function timestampOverrideDeserializer(defaultValue: FormData) { + return { + timestampOverride: defaultValue.timestamp_override.field_name, + timestampOverrideFallbackDisabled: defaultValue.timestamp_override.fallback_disabled ?? false, + }; +} + +export function timestampOverrideSerializer(formData: FormData): { + timestamp_override: TimestampOverrideObject | undefined; +} { + if (formData.timestampOverride === '') { + return { timestamp_override: undefined }; + } + + return { + timestamp_override: { + field_name: formData.timestampOverride, + fallback_disabled: formData.timestampOverrideFallbackDisabled, + }, + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/utils.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/utils.ts new file mode 100644 index 000000000000..bd78bb5e9ed2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/utils.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DataSourceType } from '../../../../../../detections/pages/detection_engine/rules/types'; +import { DataSourceType as DataSourceTypeSnakeCase } from '../../../../../../../common/api/detection_engine'; +import type { DiffableRule } from '../../../../../../../common/api/detection_engine'; + +interface UseRuleIndexPatternParameters { + dataSourceType: DataSourceType; + index: string[]; + dataViewId: string | undefined; +} + +export function getUseRuleIndexPatternParameters( + finalDiffableRule: DiffableRule, + defaultIndexPattern: string[] +): UseRuleIndexPatternParameters { + if (!('data_source' in finalDiffableRule) || !finalDiffableRule.data_source) { + return { + dataSourceType: DataSourceType.IndexPatterns, + index: defaultIndexPattern, + dataViewId: undefined, + }; + } + if (finalDiffableRule.data_source.type === DataSourceTypeSnakeCase.data_view) { + return { + dataSourceType: DataSourceType.DataView, + index: [], + dataViewId: finalDiffableRule.data_source.data_view_id, + }; + } + return { + dataSourceType: DataSourceType.IndexPatterns, + index: finalDiffableRule.data_source.index_patterns, + dataViewId: undefined, + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/common_rule_field_readonly.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/common_rule_field_readonly.tsx index bc4f1928ef9b..6c502b2e4178 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/common_rule_field_readonly.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/common_rule_field_readonly.tsx @@ -45,7 +45,7 @@ export function CommonRuleFieldReadOnly({ }: CommonRuleFieldReadOnlyProps) { switch (fieldName) { case 'building_block': - return ; + return ; case 'description': return ; case 'investigation_fields': diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/building_block/building_block.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/building_block/building_block.tsx index 84edd7932a2d..7e64c140e6d7 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/building_block/building_block.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_readonly/fields/building_block/building_block.tsx @@ -9,8 +9,17 @@ import React from 'react'; import { EuiDescriptionList } from '@elastic/eui'; import * as ruleDetailsI18n from '../../../../translations'; import { BuildingBlock } from '../../../../rule_about_section'; +import type { BuildingBlockObject } from '../../../../../../../../../common/api/detection_engine'; + +interface BuildingBlockReadOnlyProps { + buildingBlock?: BuildingBlockObject; +} + +export function BuildingBlockReadOnly({ buildingBlock }: BuildingBlockReadOnlyProps) { + if (!buildingBlock || !buildingBlock.type) { + return null; + } -export function BuildingBlockReadOnly() { return ( { + if (threat.length === 0) { + return null; + } + return ( { + return useIsExperimentalFeatureEnabled('prebuiltRulesCustomizationEnabled'); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/prebuilt_rules/use_perform_rule_upgrade.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/prebuilt_rules/use_perform_rule_upgrade.ts index aa9e38217a19..f82812f7ac9d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/prebuilt_rules/use_perform_rule_upgrade.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/prebuilt_rules/use_perform_rule_upgrade.ts @@ -4,29 +4,20 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import type { PickVersionValues } from '../../../../../common/api/detection_engine'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { usePerformAllRulesUpgradeMutation } from '../../api/hooks/prebuilt_rules/use_perform_all_rules_upgrade_mutation'; import { usePerformSpecificRulesUpgradeMutation } from '../../api/hooks/prebuilt_rules/use_perform_specific_rules_upgrade_mutation'; import * as i18n from './translations'; -export const usePerformUpgradeAllRules = () => { - const { addError, addSuccess } = useAppToasts(); - - return usePerformAllRulesUpgradeMutation({ - onError: (err) => { - addError(err, { title: i18n.RULE_UPGRADE_FAILED }); - }, - onSuccess: (result) => { - addSuccess(getSuccessToastMessage(result)); - }, - }); -}; - -export const usePerformUpgradeSpecificRules = () => { +export const usePerformUpgradeSpecificRules = ({ + pickVersion, +}: { + pickVersion: PickVersionValues; +}) => { const { addError, addSuccess } = useAppToasts(); - return usePerformSpecificRulesUpgradeMutation({ + return usePerformSpecificRulesUpgradeMutation(pickVersion, { onError: (err) => { addError(err, { title: i18n.RULE_UPGRADE_FAILED }); }, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts index e12442c97aa4..59ac52d592bc 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts @@ -99,6 +99,7 @@ export interface FilterOptions { excludeRuleTypes?: Type[]; enabled?: boolean; // undefined is to display all the rules ruleExecutionStatus?: RuleExecutionStatus; // undefined means "all" + ruleSource?: RuleCustomizationEnum[]; // undefined is to display all the rules } export interface FetchRulesResponse { @@ -202,3 +203,8 @@ export interface FindRulesReferencedByExceptionsProps { lists: FindRulesReferencedByExceptionsListProp[]; signal?: AbortSignal; } + +export enum RuleCustomizationEnum { + customized = 'CUSTOMIZED', + not_customized = 'NOT_CUSTOMIZED', +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx index 68e58b4db073..22f10605b368 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx @@ -45,6 +45,7 @@ import type { ExecuteBulkActionsDryRun } from './use_bulk_actions_dry_run'; import { computeDryRunEditPayload } from './utils/compute_dry_run_edit_payload'; import { transformExportDetailsToDryRunResult } from './utils/dry_run_result'; import { prepareSearchParams } from './utils/prepare_search_params'; +import { ManualRuleRunEventTypes } from '../../../../../common/lib/telemetry'; interface UseBulkActionsArgs { filterOptions: FilterOptions; @@ -234,7 +235,7 @@ export const useBulkActions = ({ } const modalManualRuleRunConfirmationResult = await showManualRuleRunConfirmation(); - startServices.telemetry.reportManualRuleRunOpenModal({ + startServices.telemetry.reportEvent(ManualRuleRunEventTypes.ManualRuleRunOpenModal, { type: 'bulk', }); if (modalManualRuleRunConfirmationResult === null) { @@ -252,7 +253,7 @@ export const useBulkActions = ({ }, }); - startServices.telemetry.reportManualRuleRunExecute({ + startServices.telemetry.reportEvent(ManualRuleRunEventTypes.ManualRuleRunExecute, { rangeInMs: modalManualRuleRunConfirmationResult.endDate.diff( modalManualRuleRunConfirmationResult.startDate ), diff --git a/x-pack/plugins/security_solution/public/detections/components/modals/ml_job_upgrade_modal/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/ml_job_upgrade_modal/index.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detections/components/modals/ml_job_upgrade_modal/index.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/ml_job_upgrade_modal/index.tsx diff --git a/x-pack/plugins/security_solution/public/detections/components/modals/ml_job_upgrade_modal/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/ml_job_upgrade_modal/translations.tsx similarity index 95% rename from x-pack/plugins/security_solution/public/detections/components/modals/ml_job_upgrade_modal/translations.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/ml_job_upgrade_modal/translations.tsx index 8163eca279cf..caf94e5c1a26 100644 --- a/x-pack/plugins/security_solution/public/detections/components/modals/ml_job_upgrade_modal/translations.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/ml_job_upgrade_modal/translations.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { MlJobCompatibilityLink } from '../../../../common/components/links_to_docs'; +import { MlJobCompatibilityLink } from '../../../../../../../common/components/links_to_docs'; export const ML_JOB_UPGRADE_MODAL_TITLE = i18n.translate( 'xpack.securitySolution.detectionEngine.mlJobUpgradeModal.messageTitle', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/upgrade_conflicts_modal/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/upgrade_conflicts_modal/index.tsx new file mode 100644 index 000000000000..0c664398c51f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/upgrade_conflicts_modal/index.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiConfirmModal, EuiText } from '@elastic/eui'; +import React, { memo } from 'react'; +import * as i18n from './translations'; + +export interface UpgradeConflictsModalProps { + onCancel: ( + event?: React.KeyboardEvent | React.MouseEvent + ) => void; + onConfirm?: (event: React.MouseEvent) => void; +} + +const UpgradeConflictsModalComponent = ({ onCancel, onConfirm }: UpgradeConflictsModalProps) => { + return ( + + {i18n.UPGRADE_CONFLICTS_MODAL_BODY} + + ); +}; + +export const UpgradeConflictsModal = memo(UpgradeConflictsModalComponent); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/upgrade_conflicts_modal/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/upgrade_conflicts_modal/translations.tsx new file mode 100644 index 000000000000..bc5738b879cc --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/modals/upgrade_conflicts_modal/translations.tsx @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const UPGRADE_CONFLICTS_MODAL_TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeConflictsModal.messageTitle', + { + defaultMessage: 'Update rules without conflicts?', + } +); + +export const UPGRADE_CONFLICTS_MODAL_CANCEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeConflictsModal.cancelTitle', + { + defaultMessage: 'Cancel', + } +); + +export const UPGRADE_CONFLICTS_MODAL_CONFIRM = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeConflictsModal.confirmTitle', + { + defaultMessage: 'Update rules without conflicts', + } +); + +export const UPGRADE_CONFLICTS_MODAL_BODY = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeConflictsModal.affectedJobsTitle', + { + defaultMessage: + "Some of the selected rules have conflicts and, for that reason, won't be updated. Resolve the conflicts to properly update the rules.", + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts index 026c35f664bb..5db5d0eee748 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts @@ -24,6 +24,27 @@ export const UPDATE_SELECTED_RULES = (numberOfSelectedRules: number) => { ); }; +export const BULK_UPDATE_BUTTON_TOOLTIP_NO_PERMISSIONS = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.bulkButtons.noPermissions', + { + defaultMessage: "You don't have permissions to update rules", + } +); + +export const BULK_UPDATE_ALL_RULES_BUTTON_TOOLTIP_CONFLICTS = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.bulkButtons.allRules.conflicts', + { + defaultMessage: 'All rules have conflicts. Update them individually.', + } +); + +export const BULK_UPDATE_SELECTED_RULES_BUTTON_TOOLTIP_CONFLICTS = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.bulkButtons.selectedRules.conflicts', + { + defaultMessage: 'All selected rules have conflicts. Update them individually.', + } +); + export const SEARCH_PLACEHOLDER = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.upgradeRules.searchBarPlaceholder', { @@ -37,6 +58,12 @@ export const UPDATE_BUTTON_LABEL = i18n.translate( defaultMessage: 'Update', } ); +export const UPDATE_ERROR = i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleDetails.updateError', + { + defaultMessage: 'Update error', + } +); export const UPDATE_FLYOUT_PER_FIELD_TOOLTIP_DESCRIPTION = i18n.translate( 'xpack.securitySolution.detectionEngine.ruleDetails.perFieldTooltip', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_buttons.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_buttons.tsx index 1d0e6adeabce..8a1d20114965 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_buttons.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_buttons.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiToolTip } from '@elastic/eui'; import React, { useCallback } from 'react'; import type { RuleUpgradeState } from '../../../../rule_management/model/prebuilt_rule_upgrade'; import { useUserData } from '../../../../../detections/components/user_info'; @@ -20,8 +20,15 @@ export const UpgradePrebuiltRulesTableButtons = ({ selectedRules, }: UpgradePrebuiltRulesTableButtonsProps) => { const { - state: { hasRulesToUpgrade, loadingRules, isRefetching, isUpgradingSecurityPackages }, - actions: { upgradeAllRules, upgradeRules }, + state: { + ruleUpgradeInfos, + hasRulesToUpgrade, + loadingRules, + isRefetching, + isUpgradingSecurityPackages, + isPrebuiltRulesCustomizationEnabled, + }, + actions: { upgradeRules }, } = useUpgradePrebuiltRulesTableContext(); const [{ loading: isUserDataLoading, canUserCRUD }] = useUserData(); const canUserEditRules = canUserCRUD && !isUserDataLoading; @@ -31,39 +38,115 @@ export const UpgradePrebuiltRulesTableButtons = ({ const isRuleUpgrading = loadingRules.length > 0; const isRequestInProgress = isRuleUpgrading || isRefetching || isUpgradingSecurityPackages; + const doAllSelectedRulesHaveConflicts = + isPrebuiltRulesCustomizationEnabled && isAllRuleHaveConflicts(selectedRules); + const doAllRulesHaveConflicts = + isPrebuiltRulesCustomizationEnabled && isAllRuleHaveConflicts(ruleUpgradeInfos); + + const { selectedRulesButtonTooltip, allRulesButtonTooltip } = useBulkUpdateButtonsTooltipContent({ + canUserEditRules, + doAllSelectedRulesHaveConflicts, + doAllRulesHaveConflicts, + isPrebuiltRulesCustomizationEnabled, + }); + const upgradeSelectedRules = useCallback( () => upgradeRules(selectedRules.map((rule) => rule.rule_id)), [selectedRules, upgradeRules] ); + const upgradeAllRules = useCallback( + // Upgrade all rules, ignoring filter and selection + () => upgradeRules(ruleUpgradeInfos.map((rule) => rule.rule_id)), + [ruleUpgradeInfos, upgradeRules] + ); + return ( {shouldDisplayUpgradeSelectedRulesButton ? ( - - <> - {i18n.UPDATE_SELECTED_RULES(numberOfSelectedRules)} - {isRuleUpgrading ? : undefined} - - + + + <> + {i18n.UPDATE_SELECTED_RULES(numberOfSelectedRules)} + {isRuleUpgrading ? : undefined} + + + ) : null} - - {i18n.UPDATE_ALL} - {isRuleUpgrading ? : undefined} - + + + {i18n.UPDATE_ALL} + {isRuleUpgrading ? : undefined} + + ); }; + +const useBulkUpdateButtonsTooltipContent = ({ + canUserEditRules, + doAllSelectedRulesHaveConflicts, + doAllRulesHaveConflicts, + isPrebuiltRulesCustomizationEnabled, +}: { + canUserEditRules: boolean | null; + doAllSelectedRulesHaveConflicts: boolean; + doAllRulesHaveConflicts: boolean; + isPrebuiltRulesCustomizationEnabled: boolean; +}) => { + if (!canUserEditRules) { + return { + selectedRulesButtonTooltip: i18n.BULK_UPDATE_BUTTON_TOOLTIP_NO_PERMISSIONS, + allRulesButtonTooltip: i18n.BULK_UPDATE_BUTTON_TOOLTIP_NO_PERMISSIONS, + }; + } + + if (!isPrebuiltRulesCustomizationEnabled) { + return { + selectedRulesButtonTooltip: undefined, + allRulesButtonTooltip: undefined, + }; + } + + if (doAllRulesHaveConflicts) { + return { + selectedRulesButtonTooltip: i18n.BULK_UPDATE_SELECTED_RULES_BUTTON_TOOLTIP_CONFLICTS, + allRulesButtonTooltip: i18n.BULK_UPDATE_ALL_RULES_BUTTON_TOOLTIP_CONFLICTS, + }; + } + + if (doAllSelectedRulesHaveConflicts) { + return { + selectedRulesButtonTooltip: i18n.BULK_UPDATE_SELECTED_RULES_BUTTON_TOOLTIP_CONFLICTS, + allRulesButtonTooltip: undefined, + }; + } + + return { + selectedRulesButtonTooltip: undefined, + allRulesButtonTooltip: undefined, + }; +}; + +function isAllRuleHaveConflicts(rules: Array<{ diff: { num_fields_with_conflicts: number } }>) { + return rules.every((rule) => rule.diff.num_fields_with_conflicts > 0); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx index aad1e053e15b..cbb0350da173 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx @@ -8,36 +8,37 @@ import type { Dispatch, SetStateAction } from 'react'; import React, { createContext, useCallback, useContext, useMemo, useState } from 'react'; import { EuiButton, EuiToolTip } from '@elastic/eui'; +import { useIsPrebuiltRulesCustomizationEnabled } from '../../../../rule_management/hooks/use_is_prebuilt_rules_customization_enabled'; +import { useAppToasts } from '../../../../../common/hooks/use_app_toasts'; +import type { RuleUpgradeInfoForReview } from '../../../../../../common/api/detection_engine'; import type { RulesUpgradeState } from '../../../../rule_management/model/prebuilt_rule_upgrade'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import { RuleUpgradeConflictsResolverTab } from '../../../../rule_management/components/rule_details/three_way_diff/rule_upgrade_conflicts_resolver_tab'; import { PerFieldRuleDiffTab } from '../../../../rule_management/components/rule_details/per_field_rule_diff_tab'; import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages'; -import { useInstalledSecurityJobs } from '../../../../../common/components/ml/hooks/use_installed_security_jobs'; -import { useBoolState } from '../../../../../common/hooks/use_bool_state'; -import { affectedJobIds } from '../../../../../detections/components/callouts/ml_job_compatibility_callout/affected_job_ids'; import type { RuleResponse, RuleSignatureId, } from '../../../../../../common/api/detection_engine/model/rule_schema'; import { invariant } from '../../../../../../common/utils/invariant'; -import { - usePerformUpgradeAllRules, - usePerformUpgradeSpecificRules, -} from '../../../../rule_management/logic/prebuilt_rules/use_perform_rule_upgrade'; +import { usePerformUpgradeSpecificRules } from '../../../../rule_management/logic/prebuilt_rules/use_perform_rule_upgrade'; import { usePrebuiltRulesUpgradeReview } from '../../../../rule_management/logic/prebuilt_rules/use_prebuilt_rules_upgrade_review'; import type { UpgradePrebuiltRulesTableFilterOptions } from './use_filter_prebuilt_rules_to_upgrade'; import { useFilterPrebuiltRulesToUpgrade } from './use_filter_prebuilt_rules_to_upgrade'; -import { useAsyncConfirmation } from '../rules_table/use_async_confirmation'; import { TabContentPadding } from '../../../../rule_management/components/rule_details/rule_details_flyout'; import { RuleDiffTab } from '../../../../rule_management/components/rule_details/rule_diff_tab'; -import { MlJobUpgradeModal } from '../../../../../detections/components/modals/ml_job_upgrade_modal'; +import { MlJobUpgradeModal } from './modals/ml_job_upgrade_modal'; +import { UpgradeConflictsModal } from './modals/upgrade_conflicts_modal'; import * as ruleDetailsI18n from '../../../../rule_management/components/rule_details/translations'; import * as i18n from './translations'; import { usePrebuiltRulesUpgradeState } from './use_prebuilt_rules_upgrade_state'; import { useRulePreviewFlyout } from '../use_rule_preview_flyout'; +import { useMlJobUpgradeModal, useUpgradeConflictsModal } from './use_upgrade_modals'; export interface UpgradePrebuiltRulesTableState { + /** + * Rule upgrade state (all rules available for upgrade) + */ + ruleUpgradeInfos: RuleUpgradeInfoForReview[]; /** * Rule upgrade state after applying `filterOptions` */ @@ -90,7 +91,6 @@ export const PREBUILT_RULE_UPDATE_FLYOUT_ANCHOR = 'updatePrebuiltRulePreview'; export interface UpgradePrebuiltRulesTableActions { reFetchRules: () => void; upgradeRules: (ruleIds: RuleSignatureId[]) => void; - upgradeAllRules: () => void; setFilterOptions: Dispatch>; openRulePreview: (ruleId: string) => void; } @@ -111,14 +111,14 @@ interface UpgradePrebuiltRulesTableContextProviderProps { export const UpgradePrebuiltRulesTableContextProvider = ({ children, }: UpgradePrebuiltRulesTableContextProviderProps) => { - const isPrebuiltRulesCustomizationEnabled = useIsExperimentalFeatureEnabled( - 'prebuiltRulesCustomizationEnabled' - ); + const isPrebuiltRulesCustomizationEnabled = useIsPrebuiltRulesCustomizationEnabled(); const [loadingRules, setLoadingRules] = useState([]); const [filterOptions, setFilterOptions] = useState({ filter: '', tags: [], + ruleSource: [], }); + const { addError } = useAppToasts(); const isUpgradingSecurityPackages = useIsUpgradingSecurityPackages(); @@ -143,21 +143,41 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ const { rulesUpgradeState, setRuleFieldResolvedValue } = usePrebuiltRulesUpgradeState(filteredRuleUpgradeInfos); - // Wrapper to add confirmation modal for users who may be running older ML Jobs that would - // be overridden by updating their rules. For details, see: https://github.com/elastic/kibana/issues/128121 - const [isUpgradeModalVisible, showUpgradeModal, hideUpgradeModal] = useBoolState(false); - const { loading: loadingJobs, jobs } = useInstalledSecurityJobs(); - const legacyJobsInstalled = jobs.filter((job) => affectedJobIds.includes(job.id)); + const { + isVisible: isLegacyMLJobsModalVisible, + legacyJobsInstalled, + confirmLegacyMLJobs, + handleConfirm: handleLegacyMLJobsConfirm, + handleCancel: handleLegacyMLJobsCancel, + loadingJobs, + } = useMlJobUpgradeModal(); + + const { + isVisible: isConflictsModalVisible, + confirmConflictsUpgrade, + handleConfirm: handleConflictsConfirm, + handleCancel: handleConflictsCancel, + } = useUpgradeConflictsModal(); - const [confirmUpgrade, handleUpgradeConfirm, handleUpgradeCancel] = useAsyncConfirmation({ - onInit: showUpgradeModal, - onFinish: hideUpgradeModal, - }); + const shouldConfirmMLJobs = legacyJobsInstalled.length > 0; + const getRulesWithConflicts = useCallback( + (ruleIds?: RuleSignatureId[]) => { + const rulesToUpgrade = + ruleIds?.map((ruleId) => { + const rule = rulesUpgradeState[ruleId]; + invariant(rule, `Rule with ID ${ruleId} not found.`); - const shouldConfirmUpgrade = legacyJobsInstalled.length > 0; + return rule; + }) ?? []; + + return rulesToUpgrade.filter((rule) => rule.diff.num_fields_with_conflicts > 0); + }, + [rulesUpgradeState] + ); - const { mutateAsync: upgradeAllRulesRequest } = usePerformUpgradeAllRules(); - const { mutateAsync: upgradeSpecificRulesRequest } = usePerformUpgradeSpecificRules(); + const { mutateAsync: upgradeSpecificRulesRequest } = usePerformUpgradeSpecificRules({ + pickVersion: isPrebuiltRulesCustomizationEnabled ? 'MERGED' : 'TARGET', + }); const upgradeRules = useCallback( async (ruleIds: RuleSignatureId[]) => { @@ -170,32 +190,47 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ })); setLoadingRules((prev) => [...prev, ...rulesToUpgrade.map((r) => r.rule_id)]); try { - if (shouldConfirmUpgrade && !(await confirmUpgrade())) { + // Handle MLJobs modal + if (shouldConfirmMLJobs && !(await confirmLegacyMLJobs())) { + return; + } + + // Handle Rule Upgrades modal + const rulesWithConflicts = getRulesWithConflicts(ruleIds); + if ( + isPrebuiltRulesCustomizationEnabled && + rulesWithConflicts.length > 0 && + !(await confirmConflictsUpgrade()) + ) { return; } - await upgradeSpecificRulesRequest(rulesToUpgrade); + + // Prepare payload for upgrade with rules with no conflicts + const ruleIdsWithConflicts = new Set(rulesWithConflicts.map((rule) => rule.rule_id)); + const rulesToUpgradeWithNoConflicts = isPrebuiltRulesCustomizationEnabled + ? rulesToUpgrade.filter((rule) => !ruleIdsWithConflicts.has(rule.rule_id)) + : rulesToUpgrade; + await upgradeSpecificRulesRequest(rulesToUpgradeWithNoConflicts); + } catch (err) { + addError(err, { title: i18n.UPDATE_ERROR }); } finally { setLoadingRules((prev) => prev.filter((id) => !rulesToUpgrade.some((r) => r.rule_id === id)) ); } }, - [confirmUpgrade, shouldConfirmUpgrade, rulesUpgradeState, upgradeSpecificRulesRequest] + [ + confirmLegacyMLJobs, + confirmConflictsUpgrade, + shouldConfirmMLJobs, + getRulesWithConflicts, + rulesUpgradeState, + upgradeSpecificRulesRequest, + isPrebuiltRulesCustomizationEnabled, + addError, + ] ); - const upgradeAllRules = useCallback(async () => { - // Unselect all rules so that the table doesn't show the "bulk actions" bar - setLoadingRules((prev) => [...prev, ...ruleUpgradeInfos.map((r) => r.rule_id)]); - try { - if (shouldConfirmUpgrade && !(await confirmUpgrade())) { - return; - } - await upgradeAllRulesRequest(); - } finally { - setLoadingRules([]); - } - }, [confirmUpgrade, ruleUpgradeInfos, shouldConfirmUpgrade, upgradeAllRulesRequest]); - const ruleActionsFactory = useCallback( (rule: RuleResponse, closeRulePreview: () => void) => ( ({ reFetchRules: refetch, upgradeRules, - upgradeAllRules, setFilterOptions, openRulePreview, }), - [refetch, upgradeRules, upgradeAllRules, openRulePreview] + [refetch, upgradeRules, openRulePreview] ); const providerValue = useMemo(() => { return { state: { + ruleUpgradeInfos, rulesUpgradeState, hasRulesToUpgrade: isFetched && ruleUpgradeInfos.length > 0, filterOptions, @@ -344,11 +379,17 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ return ( <> - {isUpgradeModalVisible && ( + {isLegacyMLJobsModalVisible && ( + )} + {isConflictsModalVisible && ( + )} {children} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_filters.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_filters.tsx index 215a810bf3aa..900d81d0b003 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_filters.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_filters.tsx @@ -9,10 +9,13 @@ import { EuiFilterGroup, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { isEqual } from 'lodash/fp'; import React, { useCallback } from 'react'; import styled from 'styled-components'; +import { useIsPrebuiltRulesCustomizationEnabled } from '../../../../rule_management/hooks/use_is_prebuilt_rules_customization_enabled'; +import type { RuleCustomizationEnum } from '../../../../rule_management/logic'; import * as i18n from './translations'; import { TagsFilterPopover } from '../rules_table_filters/tags_filter_popover'; import { RuleSearchField } from '../rules_table_filters/rule_search_field'; import { useUpgradePrebuiltRulesTableContext } from './upgrade_prebuilt_rules_table_context'; +import { RuleCustomizationFilterPopover } from './upgrade_rule_customization_filter_popover'; const FilterWrapper = styled(EuiFlexGroup)` margin-bottom: ${({ theme }) => theme.eui.euiSizeM}; @@ -28,7 +31,9 @@ const UpgradePrebuiltRulesTableFiltersComponent = () => { actions: { setFilterOptions }, } = useUpgradePrebuiltRulesTableContext(); - const { tags: selectedTags } = filterOptions; + const isPrebuiltRulesCustomizationEnabled = useIsPrebuiltRulesCustomizationEnabled(); + + const { tags: selectedTags, ruleSource: selectedRuleSource = [] } = filterOptions; const handleOnSearch = useCallback( (filterString: string) => { @@ -52,22 +57,45 @@ const UpgradePrebuiltRulesTableFiltersComponent = () => { [selectedTags, setFilterOptions] ); + const handleSelectedRuleSource = useCallback( + (newRuleSource: RuleCustomizationEnum[]) => { + if (!isEqual(newRuleSource, selectedRuleSource)) { + setFilterOptions((filters) => ({ + ...filters, + ruleSource: newRuleSource, + })); + } + }, + [selectedRuleSource, setFilterOptions] + ); + return ( - + - - - + + {isPrebuiltRulesCustomizationEnabled && ( + + + + )} + + + + ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_rule_customization_filter_popover.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_rule_customization_filter_popover.tsx new file mode 100644 index 000000000000..234943e33327 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_rule_customization_filter_popover.tsx @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState, useMemo } from 'react'; +import type { EuiSelectableOption } from '@elastic/eui'; +import { EuiFilterButton, EuiPopover, EuiSelectable } from '@elastic/eui'; +import { RuleCustomizationEnum } from '../../../../rule_management/logic'; +import * as i18n from '../../../../../detections/pages/detection_engine/rules/translations'; +import { toggleSelectedGroup } from '../../../../../common/components/ml_popover/jobs_table/filters/toggle_selected_group'; + +interface RuleCustomizationFilterPopoverProps { + selectedRuleSource: RuleCustomizationEnum[]; + onSelectedRuleSourceChanged: (newRuleSource: RuleCustomizationEnum[]) => void; +} + +const RULE_CUSTOMIZATION_POPOVER_WIDTH = 200; + +const RuleCustomizationFilterPopoverComponent = ({ + selectedRuleSource, + onSelectedRuleSourceChanged, +}: RuleCustomizationFilterPopoverProps) => { + const [isRuleCustomizationPopoverOpen, setIsRuleCustomizationPopoverOpen] = useState(false); + + const selectableOptions: EuiSelectableOption[] = useMemo( + () => [ + { + label: i18n.MODIFIED_LABEL, + key: RuleCustomizationEnum.customized, + checked: selectedRuleSource.includes(RuleCustomizationEnum.customized) ? 'on' : undefined, + }, + { + label: i18n.UNMODIFIED_LABEL, + key: RuleCustomizationEnum.not_customized, + checked: selectedRuleSource.includes(RuleCustomizationEnum.not_customized) + ? 'on' + : undefined, + }, + ], + [selectedRuleSource] + ); + + const handleSelectableOptionsChange = ( + newOptions: EuiSelectableOption[], + _: unknown, + changedOption: EuiSelectableOption + ) => { + toggleSelectedGroup( + changedOption.key ?? '', + selectedRuleSource, + onSelectedRuleSourceChanged as (args: string[]) => void + ); + }; + + const triggerButton = ( + setIsRuleCustomizationPopoverOpen(!isRuleCustomizationPopoverOpen)} + numFilters={selectableOptions.length} + isSelected={isRuleCustomizationPopoverOpen} + hasActiveFilters={selectedRuleSource.length > 0} + numActiveFilters={selectedRuleSource.length} + data-test-subj="rule-customization-filter-popover-button" + > + {i18n.RULE_SOURCE} + + ); + + return ( + setIsRuleCustomizationPopoverOpen(!isRuleCustomizationPopoverOpen)} + panelPaddingSize="none" + repositionOnScroll + panelProps={{ + 'data-test-subj': 'rule-customization-filter-popover', + }} + > + + {(list) =>
    {list}
    } +
    +
    + ); +}; + +export const RuleCustomizationFilterPopover = React.memo(RuleCustomizationFilterPopoverComponent); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_filter_prebuilt_rules_to_upgrade.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_filter_prebuilt_rules_to_upgrade.ts index 342a1e6e8768..b5a0e123d751 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_filter_prebuilt_rules_to_upgrade.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_filter_prebuilt_rules_to_upgrade.ts @@ -7,9 +7,12 @@ import { useMemo } from 'react'; import type { RuleUpgradeInfoForReview } from '../../../../../../common/api/detection_engine/prebuilt_rules'; -import type { FilterOptions } from '../../../../rule_management/logic/types'; +import { RuleCustomizationEnum, type FilterOptions } from '../../../../rule_management/logic/types'; -export type UpgradePrebuiltRulesTableFilterOptions = Pick; +export type UpgradePrebuiltRulesTableFilterOptions = Pick< + FilterOptions, + 'filter' | 'tags' | 'ruleSource' +>; export const useFilterPrebuiltRulesToUpgrade = ({ rules, @@ -19,7 +22,7 @@ export const useFilterPrebuiltRulesToUpgrade = ({ filterOptions: UpgradePrebuiltRulesTableFilterOptions; }) => { const filteredRules = useMemo(() => { - const { filter, tags } = filterOptions; + const { filter, tags, ruleSource } = filterOptions; return rules.filter((ruleInfo) => { if (filter && !ruleInfo.current_rule.name.toLowerCase().includes(filter.toLowerCase())) { return false; @@ -29,6 +32,25 @@ export const useFilterPrebuiltRulesToUpgrade = ({ return tags.every((tag) => ruleInfo.current_rule.tags.includes(tag)); } + if (ruleSource && ruleSource.length > 0) { + if ( + ruleSource.includes(RuleCustomizationEnum.customized) && + ruleSource.includes(RuleCustomizationEnum.not_customized) + ) { + return true; + } else if ( + ruleSource.includes(RuleCustomizationEnum.customized) && + ruleInfo.current_rule.rule_source.type === 'external' + ) { + return ruleInfo.current_rule.rule_source.is_customized; + } else if ( + ruleSource.includes(RuleCustomizationEnum.not_customized) && + ruleInfo.current_rule.rule_source.type === 'external' + ) { + return ruleInfo.current_rule.rule_source.is_customized === false; + } + } + return true; }); }, [filterOptions, rules]); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state.ts index 29c5b2b201fe..8c97a4ef52e2 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_prebuilt_rules_upgrade_state.ts @@ -6,7 +6,7 @@ */ import { useCallback, useMemo, useState } from 'react'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; +import { useIsPrebuiltRulesCustomizationEnabled } from '../../../../rule_management/hooks/use_is_prebuilt_rules_customization_enabled'; import type { RulesUpgradeState, FieldsUpgradeState, @@ -33,9 +33,7 @@ interface UseRulesUpgradeStateResult { export function usePrebuiltRulesUpgradeState( ruleUpgradeInfos: RuleUpgradeInfoForReview[] ): UseRulesUpgradeStateResult { - const isPrebuiltRulesCustomizationEnabled = useIsExperimentalFeatureEnabled( - 'prebuiltRulesCustomizationEnabled' - ); + const isPrebuiltRulesCustomizationEnabled = useIsPrebuiltRulesCustomizationEnabled(); const [rulesResolvedConflicts, setRulesResolvedConflicts] = useState({}); const setRuleFieldResolvedValue = useCallback( diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_modals.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_modals.tsx new file mode 100644 index 000000000000..3e20d914dabc --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_modals.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useInstalledSecurityJobs } from '../../../../../common/components/ml/hooks/use_installed_security_jobs'; +import { useBoolState } from '../../../../../common/hooks/use_bool_state'; +import { affectedJobIds } from '../../../../../../common/machine_learning/affected_job_ids'; +import { useAsyncConfirmation } from '../rules_table/use_async_confirmation'; + +export const useMlJobUpgradeModal = () => { + const [isVisible, showModal, hideModal] = useBoolState(false); + const { loading: loadingJobs, jobs } = useInstalledSecurityJobs(); + const legacyJobsInstalled = jobs.filter((job) => affectedJobIds.includes(job.id)); + const [confirmLegacyMLJobs, handleConfirm, handleCancel] = useAsyncConfirmation({ + onInit: showModal, + onFinish: hideModal, + }); + + return { + isVisible, + legacyJobsInstalled, + confirmLegacyMLJobs, + handleConfirm, + handleCancel, + loadingJobs, + }; +}; + +export const useUpgradeConflictsModal = () => { + const [isVisible, showModal, hideModal] = useBoolState(false); + const [confirmConflictsUpgrade, handleConfirm, handleCancel] = useAsyncConfirmation({ + onInit: showModal, + onFinish: hideModal, + }); + + return { + isVisible, + confirmConflictsUpgrade, + handleConfirm, + handleCancel, + }; +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_prebuilt_rules_table_columns.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_prebuilt_rules_table_columns.tsx index 09009c98c285..c2b1f8e3dbe4 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_prebuilt_rules_table_columns.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_prebuilt_rules_table_columns.tsx @@ -6,7 +6,14 @@ */ import type { EuiBasicTableColumn } from '@elastic/eui'; -import { EuiBadge, EuiButtonEmpty, EuiLink, EuiLoadingSpinner, EuiText } from '@elastic/eui'; +import { + EuiBadge, + EuiButtonEmpty, + EuiLink, + EuiLoadingSpinner, + EuiText, + EuiToolTip, +} from '@elastic/eui'; import React, { useMemo } from 'react'; import type { RuleUpgradeState } from '../../../../rule_management/model/prebuilt_rule_upgrade/rule_upgrade_state'; import { RulesTableEmptyColumnName } from '../rules_table_empty_column_name'; @@ -104,6 +111,35 @@ const INTEGRATIONS_COLUMN: TableColumn = { truncateText: true, }; +const MODIFIED_COLUMN: TableColumn = { + field: 'current_rule.rule_source', + name: , + align: 'center', + render: (ruleSource: Rule['rule_source']) => { + if ( + ruleSource == null || + ruleSource.type === 'internal' || + (ruleSource.type === 'external' && ruleSource.is_customized === false) + ) { + return null; + } + + return ( + + + {i18n.MODIFIED_LABEL} + + + ); + }, + width: '90px', + truncateText: true, +}; + const createUpgradeButtonColumn = ( upgradeRules: UpgradePrebuiltRulesTableActions['upgradeRules'], loadingRules: RuleSignatureId[], @@ -124,15 +160,21 @@ const createUpgradeButtonColumn = ( /> ); + const tooltipContent = isDisabledByConflicts + ? i18n.UPDATE_RULE_BUTTON_TOOLTIP_CONFLICTS + : undefined; + return ( - upgradeRules([ruleId])} - data-test-subj={`upgradeSinglePrebuiltRuleButton-${ruleId}`} - > - {isRuleUpgrading ? spinner : i18n.UPDATE_RULE_BUTTON} - + + upgradeRules([ruleId])} + data-test-subj={`upgradeSinglePrebuiltRuleButton-${ruleId}`} + > + {isRuleUpgrading ? spinner : i18n.UPDATE_RULE_BUTTON} + + ); }, width: '10%', @@ -154,9 +196,15 @@ export const useUpgradePrebuiltRulesTableColumns = (): TableColumn[] => { } = useUpgradePrebuiltRulesTableContext(); const isDisabled = isRefetching || isUpgradingSecurityPackages; + // TODO: move this change to the `INTEGRATIONS_COLUMN` when `prebuiltRulesCustomizationEnabled` feature flag is removed + if (isPrebuiltRulesCustomizationEnabled) { + INTEGRATIONS_COLUMN.width = '70px'; + } + return useMemo( () => [ RULE_NAME_COLUMN, + ...(isPrebuiltRulesCustomizationEnabled ? [MODIFIED_COLUMN] : []), ...(showRelatedIntegrations ? [INTEGRATIONS_COLUMN] : []), TAGS_COLUMN, { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx index c38fec638e47..ae24b2bb482d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx @@ -46,6 +46,7 @@ import { useRulesTableActions } from './use_rules_table_actions'; import { MlRuleWarningPopover } from '../ml_rule_warning_popover/ml_rule_warning_popover'; import { getMachineLearningJobId } from '../../../../detections/pages/detection_engine/rules/helpers'; import type { TimeRange } from '../../../rule_gaps/types'; +import { useIsPrebuiltRulesCustomizationEnabled } from '../../../rule_management/hooks/use_is_prebuilt_rules_customization_enabled'; export type TableColumn = EuiBasicTableColumn | EuiTableActionsColumnType; @@ -233,6 +234,35 @@ const INTEGRATIONS_COLUMN: TableColumn = { truncateText: true, }; +const MODIFIED_COLUMN: TableColumn = { + field: 'rule_source', + name: , + align: 'center', + render: (ruleSource: Rule['rule_source']) => { + if ( + ruleSource == null || + ruleSource.type === 'internal' || + (ruleSource.type === 'external' && ruleSource.is_customized === false) + ) { + return null; + } + + return ( + + + {i18n.MODIFIED_LABEL} + + + ); + }, + width: '90px', + truncateText: true, +}; + const useActionsColumn = ({ showExceptionsDuplicateConfirmation, showManualRuleRunConfirmation, @@ -265,6 +295,7 @@ export const useRulesColumns = ({ }); const ruleNameColumn = useRuleNameColumn(); const [showRelatedIntegrations] = useUiSetting$(SHOW_RELATED_INTEGRATIONS_SETTING); + const isPrebuiltRulesCustomizationEnabled = useIsPrebuiltRulesCustomizationEnabled(); const enabledColumn = useEnabledColumn({ hasCRUDPermissions, isLoadingJobs, @@ -279,9 +310,15 @@ export const useRulesColumns = ({ }); const snoozeColumn = useRuleSnoozeColumn(); + // TODO: move this change to the `INTEGRATIONS_COLUMN` when `prebuiltRulesCustomizationEnabled` feature flag is removed + if (isPrebuiltRulesCustomizationEnabled) { + INTEGRATIONS_COLUMN.width = '70px'; + } + return useMemo( () => [ ruleNameColumn, + ...(isPrebuiltRulesCustomizationEnabled ? [MODIFIED_COLUMN] : []), ...(showRelatedIntegrations ? [INTEGRATIONS_COLUMN] : []), TAGS_COLUMN, { @@ -352,13 +389,14 @@ export const useRulesColumns = ({ ...(hasCRUDPermissions ? [actionsColumn] : []), ], [ - actionsColumn, - enabledColumn, + ruleNameColumn, + isPrebuiltRulesCustomizationEnabled, + showRelatedIntegrations, executionStatusColumn, snoozeColumn, + enabledColumn, hasCRUDPermissions, - ruleNameColumn, - showRelatedIntegrations, + actionsColumn, ] ); }; @@ -380,6 +418,7 @@ export const useMonitoringColumns = ({ }); const ruleNameColumn = useRuleNameColumn(); const [showRelatedIntegrations] = useUiSetting$(SHOW_RELATED_INTEGRATIONS_SETTING); + const isPrebuiltRulesCustomizationEnabled = useIsPrebuiltRulesCustomizationEnabled(); const enabledColumn = useEnabledColumn({ hasCRUDPermissions, isLoadingJobs, @@ -393,12 +432,18 @@ export const useMonitoringColumns = ({ mlJobs, }); + // TODO: move this change to the `INTEGRATIONS_COLUMN` when `prebuiltRulesCustomizationEnabled` feature flag is removed + if (isPrebuiltRulesCustomizationEnabled) { + INTEGRATIONS_COLUMN.width = '70px'; + } + return useMemo( () => [ { ...ruleNameColumn, width: '28%', }, + ...(isPrebuiltRulesCustomizationEnabled ? [MODIFIED_COLUMN] : []), ...(showRelatedIntegrations ? [INTEGRATIONS_COLUMN] : []), TAGS_COLUMN, { @@ -503,6 +548,7 @@ export const useMonitoringColumns = ({ enabledColumn, executionStatusColumn, hasCRUDPermissions, + isPrebuiltRulesCustomizationEnabled, ruleNameColumn, showRelatedIntegrations, ] diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx index 4cc7a0342665..f3d0930d7c1f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_rules_table_actions.tsx @@ -25,6 +25,7 @@ import { useDownloadExportedRules } from '../../../rule_management/logic/bulk_ac import { useHasActionsPrivileges } from './use_has_actions_privileges'; import type { TimeRange } from '../../../rule_gaps/types'; import { useScheduleRuleRun } from '../../../rule_gaps/logic/use_schedule_rule_run'; +import { ManualRuleRunEventTypes } from '../../../../common/lib/telemetry'; export const useRulesTableActions = ({ showExceptionsDuplicateConfirmation, @@ -126,7 +127,7 @@ export const useRulesTableActions = ({ onClick: async (rule: Rule) => { startTransaction({ name: SINGLE_RULE_ACTIONS.MANUAL_RULE_RUN }); const modalManualRuleRunConfirmationResult = await showManualRuleRunConfirmation(); - telemetry.reportManualRuleRunOpenModal({ + telemetry.reportEvent(ManualRuleRunEventTypes.ManualRuleRunOpenModal, { type: 'single', }); if (modalManualRuleRunConfirmationResult === null) { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/filters/execution_run_type_filter/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/filters/execution_run_type_filter/index.test.tsx index 50c35e7a6e52..a11246b4f52b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/filters/execution_run_type_filter/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/filters/execution_run_type_filter/index.test.tsx @@ -10,11 +10,12 @@ import { render, screen, fireEvent } from '@testing-library/react'; import { ExecutionRunTypeFilter } from '.'; import { RuleRunTypeEnum } from '../../../../../../../common/api/detection_engine/rule_monitoring'; import { useKibana } from '../../../../../../common/lib/kibana'; +import { EventLogEventTypes } from '../../../../../../common/lib/telemetry'; jest.mock('../../../../../../common/lib/kibana'); const mockTelemetry = { - reportEventLogFilterByRunType: jest.fn(), + reportEvent: jest.fn(), }; const mockUseKibana = useKibana as jest.Mock; @@ -28,7 +29,7 @@ mockUseKibana.mockReturnValue({ const items = [RuleRunTypeEnum.backfill, RuleRunTypeEnum.standard]; describe('ExecutionRunTypeFilter', () => { - it('calls telemetry.reportEventLogFilterByRunType on selection change', () => { + it('calls telemetry.reportEvent on selection change', () => { const handleChange = jest.fn(); render(); @@ -40,8 +41,11 @@ describe('ExecutionRunTypeFilter', () => { fireEvent.click(manualRun); expect(handleChange).toHaveBeenCalledWith([RuleRunTypeEnum.backfill]); - expect(mockTelemetry.reportEventLogFilterByRunType).toHaveBeenCalledWith({ - runType: [RuleRunTypeEnum.backfill], - }); + expect(mockTelemetry.reportEvent).toHaveBeenCalledWith( + EventLogEventTypes.EventLogFilterByRunType, + { + runType: [RuleRunTypeEnum.backfill], + } + ); }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/filters/execution_run_type_filter/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/filters/execution_run_type_filter/index.tsx index 9f144410a759..4e1c44517c05 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/filters/execution_run_type_filter/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/basic/filters/execution_run_type_filter/index.tsx @@ -15,6 +15,7 @@ import { RULE_EXECUTION_TYPE_STANDARD, } from '../../../../../../common/translations'; import { useKibana } from '../../../../../../common/lib/kibana'; +import { EventLogEventTypes } from '../../../../../../common/lib/telemetry'; interface ExecutionRunTypeFilterProps { items: RuleRunType[]; @@ -42,7 +43,9 @@ const ExecutionRunTypeFilterComponent: React.FC = ( const handleSelectionChange = useCallback( (types: RuleRunType[]) => { onChange(types); - telemetry.reportEventLogFilterByRunType({ runType: types }); + telemetry.reportEvent(EventLogEventTypes.EventLogFilterByRunType, { + runType: types, + }); }, [onChange, telemetry] ); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx index 3d284b89f074..4eeb34313401 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/actions.test.tsx @@ -57,7 +57,7 @@ import { } from '@kbn/lists-plugin/common/constants.mock'; import { of } from 'rxjs'; import { timelineDefaults } from '../../../timelines/store/defaults'; -import { defaultUdtHeaders } from '../../../timelines/components/timeline/unified_components/default_headers'; +import { defaultUdtHeaders } from '../../../timelines/components/timeline/body/column_headers/default_headers'; jest.mock('../../../timelines/containers/api', () => ({ getTimelineTemplate: jest.fn(), diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.test.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.test.tsx index cf57c9d59b08..5392d730c9e0 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.test.tsx @@ -20,6 +20,7 @@ import { useKibana as mockUseKibana } from '../../../common/lib/kibana/__mocks__ import { createTelemetryServiceMock } from '../../../common/lib/telemetry/telemetry_service.mock'; import { useQueryAlerts } from '../../containers/detection_engine/alerts/use_query'; import { getQuery, groupingSearchResponse } from './grouping_settings/mock'; +import { AlertsEventTypes } from '../../../common/lib/telemetry'; jest.mock('../../containers/detection_engine/alerts/use_query'); jest.mock('../../../sourcerer/containers'); @@ -553,17 +554,23 @@ describe('GroupedAlertsTable', () => { fireEvent.click(getByTestId('group-selector-dropdown')); fireEvent.click(getByTestId('panel-user.name')); - expect(mockedTelemetry.reportAlertsGroupingChanged).toHaveBeenCalledWith({ - groupByField: 'user.name', - tableId: testProps.tableId, - }); + expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith( + AlertsEventTypes.AlertsGroupingChanged, + { + groupByField: 'user.name', + tableId: testProps.tableId, + } + ); fireEvent.click(getByTestId('group-selector-dropdown')); fireEvent.click(getByTestId('panel-host.name')); - expect(mockedTelemetry.reportAlertsGroupingChanged).toHaveBeenCalledWith({ - groupByField: 'host.name', - tableId: testProps.tableId, - }); + expect(mockedTelemetry.reportEvent).toHaveBeenCalledWith( + AlertsEventTypes.AlertsGroupingChanged, + { + groupByField: 'host.name', + tableId: testProps.tableId, + } + ); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.tsx index a1cbdc800472..c4dd142fc71b 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/alerts_grouping.tsx @@ -25,7 +25,7 @@ import type { RunTimeMappings } from '../../../sourcerer/store/model'; import { renderGroupPanel, getStats } from './grouping_settings'; import { useKibana } from '../../../common/lib/kibana'; import { GroupedSubLevel } from './alerts_sub_grouping'; -import { track } from '../../../common/lib/telemetry'; +import { AlertsEventTypes, track } from '../../../common/lib/telemetry'; export interface AlertsTableComponentProps { currentAlertStatusFilterValue?: Status[]; @@ -80,14 +80,18 @@ const GroupedAlertsTableComponent: React.FC = (props) const { onGroupChange, onGroupToggle } = useMemo( () => ({ onGroupChange: ({ groupByField, tableId }: { groupByField: string; tableId: string }) => { - telemetry.reportAlertsGroupingChanged({ groupByField, tableId }); + telemetry.reportEvent(AlertsEventTypes.AlertsGroupingChanged, { groupByField, tableId }); }, onGroupToggle: (param: { isOpen: boolean; groupName?: string | undefined; groupNumber: number; groupingId: string; - }) => telemetry.reportAlertsGroupingToggled({ ...param, tableId: param.groupingId }), + }) => + telemetry.reportEvent(AlertsEventTypes.AlertsGroupingToggled, { + ...param, + tableId: param.groupingId, + }), }), [telemetry] ); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/grouping_settings/group_take_action_items.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/grouping_settings/group_take_action_items.tsx index 6a7b11ee0e19..e5e753b1c776 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/grouping_settings/group_take_action_items.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/grouping_settings/group_take_action_items.tsx @@ -28,7 +28,7 @@ import { import { FILTER_ACKNOWLEDGED, FILTER_CLOSED, FILTER_OPEN } from '../../../../../common/types'; import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; import * as i18n from '../translations'; -import { getTelemetryEvent, METRIC_TYPE, track } from '../../../../common/lib/telemetry'; +import { AlertsEventTypes, METRIC_TYPE, track } from '../../../../common/lib/telemetry'; import type { StartServices } from '../../../../types'; export interface TakeActionsProps { @@ -36,6 +36,18 @@ export interface TakeActionsProps { showAlertStatusActions?: boolean; } +const getTelemetryEvent = { + groupedAlertsTakeAction: ({ + tableId, + groupNumber, + status, + }: { + tableId: string; + groupNumber: number; + status: AlertWorkflowStatus; + }) => `alerts_table_${tableId}_group-${groupNumber}_mark-${status}`, +}; + export const useGroupTakeActionsItems = ({ currentStatus, showAlertStatusActions = true, @@ -58,7 +70,7 @@ export const useGroupTakeActionsItems = ({ status: 'open' | 'closed' | 'acknowledged'; groupByField: string; }) => { - telemetry.reportAlertsGroupingTakeAction(params); + telemetry.reportEvent(AlertsEventTypes.AlertsGroupingTakeAction, params); }, [telemetry] ); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.tsx index 0fa09d4bf435..60a19f005c53 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_add_to_case_actions.tsx @@ -63,7 +63,7 @@ export const useAddToCaseActions = ({ : []; }, [casesUi.helpers, ecsData, nonEcsData]); - const { activeStep, incrementStep, setStep, isTourShown } = useTourContext(); + const { activeStep, endTourStep, incrementStep, isTourShown } = useTourContext(); const onCaseSuccess = useCallback(() => { if (onSuccess) { @@ -77,9 +77,9 @@ export const useAddToCaseActions = ({ const afterCaseCreated = useCallback(async () => { if (isTourShown(SecurityStepId.alertsCases)) { - setStep(SecurityStepId.alertsCases, AlertsCasesTourSteps.viewCase); + endTourStep(SecurityStepId.alertsCases); } - }, [setStep, isTourShown]); + }, [endTourStep, isTourShown]); const prefillCasesValue = useMemo( () => diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx index a67eb08496dd..d7df06616f22 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx @@ -33,7 +33,7 @@ import { getField } from '../../../../helpers'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; import { ALERTS_ACTIONS } from '../../../../common/lib/apm/user_actions'; -import { defaultUdtHeaders } from '../../../../timelines/components/timeline/unified_components/default_headers'; +import { defaultUdtHeaders } from '../../../../timelines/components/timeline/body/column_headers/default_headers'; interface UseInvestigateInTimelineActionProps { ecsRowData?: Ecs | Ecs[] | null; diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/index.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/index.tsx index df4eb0a24968..92d42b70d240 100644 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/ml_job_compatibility_callout/index.tsx @@ -10,7 +10,7 @@ import React, { memo } from 'react'; import type { CallOutMessage } from '../../../../common/components/callouts'; import { CallOutSwitcher } from '../../../../common/components/callouts'; import { useInstalledSecurityJobs } from '../../../../common/components/ml/hooks/use_installed_security_jobs'; -import { affectedJobIds } from './affected_job_ids'; +import { affectedJobIds } from '../../../../../common/machine_learning/affected_job_ids'; import * as i18n from './translations'; const mlJobCompatibilityCalloutMessage: CallOutMessage = { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_popover/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_popover/index.tsx index 2d2875d5a873..49b6c1d1e4e9 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_popover/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_popover/index.tsx @@ -16,6 +16,7 @@ import { EuiSpacer, } from '@elastic/eui'; +import { useIsPrebuiltRulesCustomizationEnabled } from '../../../../../detection_engine/rule_management/hooks/use_is_prebuilt_rules_customization_enabled'; import type { RelatedIntegrationArray } from '../../../../../../common/api/detection_engine/model/rule_schema'; import { IntegrationDescription } from '../integrations_description'; import { useRelatedIntegrations } from '../use_related_integrations'; @@ -54,6 +55,7 @@ const IntegrationListItem = styled('li')` const IntegrationsPopoverComponent = ({ relatedIntegrations }: IntegrationsPopoverProps) => { const [isPopoverOpen, setPopoverOpen] = useState(false); const { integrations, isLoaded } = useRelatedIntegrations(relatedIntegrations); + const isPrebuiltRulesCustomizationEnabled = useIsPrebuiltRulesCustomizationEnabled(); const enabledIntegrations = useMemo(() => { return integrations.filter( @@ -65,10 +67,13 @@ const IntegrationsPopoverComponent = ({ relatedIntegrations }: IntegrationsPopov const numIntegrationsEnabled = enabledIntegrations.length; const badgeTitle = useMemo(() => { + if (isPrebuiltRulesCustomizationEnabled) { + return isLoaded ? `${numIntegrationsEnabled}/${numIntegrations}` : `${numIntegrations}`; + } return isLoaded ? `${numIntegrationsEnabled}/${numIntegrations} ${i18n.INTEGRATIONS_BADGE}` : `${numIntegrations} ${i18n.INTEGRATIONS_BADGE}`; - }, [isLoaded, numIntegrations, numIntegrationsEnabled]); + }, [isLoaded, isPrebuiltRulesCustomizationEnabled, numIntegrations, numIntegrationsEnabled]); return ( Promise.resolve(null); const showManualRuleRunConfirmation = () => Promise.resolve(null); @@ -28,7 +29,7 @@ jest.mock('../../../../detection_engine/rule_management/logic/bulk_actions/use_b jest.mock('../../../../detection_engine/rule_gaps/logic/use_schedule_rule_run'); jest.mock('../../../../common/lib/apm/use_start_transaction'); jest.mock('../../../../common/hooks/use_app_toasts'); -const mockReportManualRuleRunOpenModal = jest.fn(); +const mockReportEvent = jest.fn(); jest.mock('../../../../common/lib/kibana', () => { const actual = jest.requireActual('../../../../common/lib/kibana'); return { @@ -36,8 +37,8 @@ jest.mock('../../../../common/lib/kibana', () => { useKibana: jest.fn().mockReturnValue({ services: { telemetry: { - reportManualRuleRunOpenModal: (params: { type: 'single' | 'bulk' }) => - mockReportManualRuleRunOpenModal(params), + reportEvent: (eventType: ManualRuleRunEventTypes, params: { type: 'single' | 'bulk' }) => + mockReportEvent(eventType, params), }, application: { navigateToApp: jest.fn(), @@ -274,7 +275,7 @@ describe('RuleActionsOverflow', () => { expect(getByTestId('rules-details-popover')).not.toHaveTextContent(/.+/); }); - test('it calls telemetry.reportManualRuleRunOpenModal when rules-details-manual-rule-run is clicked', async () => { + test('it calls telemetry.reportEvent when rules-details-manual-rule-run is clicked', async () => { const { getByTestId } = render( { fireEvent.click(getByTestId('rules-details-manual-rule-run')); await waitFor(() => { - expect(mockReportManualRuleRunOpenModal).toHaveBeenCalledWith({ - type: 'single', - }); + expect(mockReportEvent).toHaveBeenCalledWith( + ManualRuleRunEventTypes.ManualRuleRunOpenModal, + { + type: 'single', + } + ); }); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx index 68defd759938..a786b95979d4 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx @@ -34,6 +34,7 @@ import { import { useDownloadExportedRules } from '../../../../detection_engine/rule_management/logic/bulk_actions/use_download_exported_rules'; import * as i18nActions from '../../../pages/detection_engine/rules/translations'; import * as i18n from './translations'; +import { ManualRuleRunEventTypes } from '../../../../common/lib/telemetry'; const MyEuiButtonIcon = styled(EuiButtonIcon)` &.euiButtonIcon { @@ -161,7 +162,7 @@ const RuleActionsOverflowComponent = ({ startTransaction({ name: SINGLE_RULE_ACTIONS.MANUAL_RULE_RUN }); closePopover(); const modalManualRuleRunConfirmationResult = await showManualRuleRunConfirmation(); - telemetry.reportManualRuleRunOpenModal({ + telemetry.reportEvent(ManualRuleRunEventTypes.ManualRuleRunOpenModal, { type: 'single', }); if (modalManualRuleRunConfirmationResult === null) { diff --git a/x-pack/plugins/security_solution/public/detections/configurations/examples/observablity_alerts/render_cell_value.tsx b/x-pack/plugins/security_solution/public/detections/configurations/examples/observablity_alerts/render_cell_value.tsx index 557a1ff9038d..761ad573a5cd 100644 --- a/x-pack/plugins/security_solution/public/detections/configurations/examples/observablity_alerts/render_cell_value.tsx +++ b/x-pack/plugins/security_solution/public/detections/configurations/examples/observablity_alerts/render_cell_value.tsx @@ -12,9 +12,9 @@ import type { EuiDataGridCellValueElementProps } from '@elastic/eui'; import { EuiLink } from '@elastic/eui'; import { ALERT_DURATION, ALERT_REASON, ALERT_SEVERITY, ALERT_STATUS } from '@kbn/rule-data-utils'; +import { useGetMappedNonEcsValue } from '../../../../common/utils/get_mapped_non_ecs_value'; import { TruncatableText } from '../../../../common/components/truncatable_text'; import { Severity } from '../../../components/severity'; -import { useGetMappedNonEcsValue } from '../../../../timelines/components/timeline/body/data_driven_columns'; import type { CellValueElementProps } from '../../../../timelines/components/timeline/cell_rendering'; import { DefaultCellRenderer } from '../../../../timelines/components/timeline/cell_rendering/default_cell_renderer'; import { Status } from '../../../components/status'; diff --git a/x-pack/plugins/security_solution/public/detections/configurations/examples/security_solution_rac/render_cell_value.tsx b/x-pack/plugins/security_solution/public/detections/configurations/examples/security_solution_rac/render_cell_value.tsx index 75b888f84f33..62eddb4b6b49 100644 --- a/x-pack/plugins/security_solution/public/detections/configurations/examples/security_solution_rac/render_cell_value.tsx +++ b/x-pack/plugins/security_solution/public/detections/configurations/examples/security_solution_rac/render_cell_value.tsx @@ -9,10 +9,10 @@ import type { EuiDataGridCellValueElementProps } from '@elastic/eui'; import { ALERT_SEVERITY, ALERT_REASON } from '@kbn/rule-data-utils'; import React from 'react'; +import { useGetMappedNonEcsValue } from '../../../../common/utils/get_mapped_non_ecs_value'; import { DefaultDraggable } from '../../../../common/components/draggables'; import { TruncatableText } from '../../../../common/components/truncatable_text'; import { Severity } from '../../../components/severity'; -import { useGetMappedNonEcsValue } from '../../../../timelines/components/timeline/body/data_driven_columns'; import type { CellValueElementProps } from '../../../../timelines/components/timeline/cell_rendering'; import { DefaultCellRenderer } from '../../../../timelines/components/timeline/cell_rendering/default_cell_renderer'; diff --git a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.tsx b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.tsx index dbd47281c5f2..484162cbf7d4 100644 --- a/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.tsx +++ b/x-pack/plugins/security_solution/public/detections/hooks/trigger_actions_alert_table/use_persistent_controls.tsx @@ -20,7 +20,7 @@ import { useSourcererDataView } from '../../../sourcerer/containers'; import { SourcererScopeName } from '../../../sourcerer/store/model'; import { updateGroups } from '../../../common/store/grouping/actions'; import { useKibana } from '../../../common/lib/kibana'; -import { METRIC_TYPE, track } from '../../../common/lib/telemetry'; +import { METRIC_TYPE, AlertsEventTypes, track } from '../../../common/lib/telemetry'; import { useDataTableFilters } from '../../../common/hooks/use_data_table_filters'; import { useDeepEqualSelector, useShallowEqualSelector } from '../../../common/hooks/use_selector'; import { RightTopMenu } from '../../../common/components/events_viewer/right_top_menu'; @@ -47,7 +47,10 @@ export const getPersistentControlsHook = (tableId: TableId) => { METRIC_TYPE.CLICK, getTelemetryEvent.groupChanged({ groupingId: tableId, selected: groupSelection }) ); - telemetry.reportAlertsGroupingChanged({ groupByField: groupSelection, tableId }); + telemetry.reportEvent(AlertsEventTypes.AlertsGroupingChanged, { + groupByField: groupSelection, + tableId, + }); }, [telemetry] ); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts index b573edd84343..cb0570855dab 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts @@ -697,6 +697,13 @@ export const COLUMN_INTEGRATIONS = i18n.translate( } ); +export const COLUMN_MODIFIED = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.columns.modifiedTitle', + { + defaultMessage: 'MODIFIED', + } +); + export const COLUMN_ENABLE = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.columns.enabledTitle', { @@ -823,6 +830,34 @@ export const NO_TAGS_AVAILABLE = i18n.translate( } ); +export const RULE_SOURCE = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.filters.ruleSourceLabel', + { + defaultMessage: 'Modifications', + } +); + +export const MODIFIED_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeRules.modifiedLabel', + { + defaultMessage: 'Modified', + } +); + +export const UNMODIFIED_LABEL = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeRules.unmodifiedLabel', + { + defaultMessage: 'Unmodified', + } +); + +export const MODIFIED_TOOLTIP = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeRules.modifiedTooltipDescription', + { + defaultMessage: 'This Elastic rule has been modified.', + } +); + export const RULE_EXECTION_STATUS_FILTER = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.filters.ruleExecutionStatusFilter', { @@ -1400,6 +1435,13 @@ export const UPDATE_RULE_BUTTON = i18n.translate( } ); +export const UPDATE_RULE_BUTTON_TOOLTIP_CONFLICTS = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.upgradeRules.button.conflicts', + { + defaultMessage: 'Rule has conflicts. Resolve them manually.', + } +); + export const GO_BACK_TO_RULES_TABLE_BUTTON = i18n.translate( 'xpack.securitySolution.addRules.goBackToRulesTableButton', { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts index 565180217f84..4f40eee5d697 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts @@ -8,7 +8,7 @@ import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import { isThreatMatchRule } from '../../../../../common/detection_engine/utils'; import { DEFAULT_TIMELINE_TITLE } from '../../../../timelines/components/timeline/translations'; -import { DEFAULT_THREAT_MATCH_QUERY } from '../../../../../common/constants'; +import { DEFAULT_MAX_SIGNALS, DEFAULT_THREAT_MATCH_QUERY } from '../../../../../common/constants'; import { DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY } from '../../../../../common/detection_engine/constants'; import type { AboutStepRule, DefineStepRule, RuleStepsOrder, ScheduleStepRule } from './types'; import { DataSourceType, GroupByOptions, RuleStep } from './types'; @@ -96,6 +96,7 @@ export const stepAboutDefaultValue: AboutStepRule = { setup: '', threatIndicatorPath: undefined, timestampOverrideFallbackDisabled: undefined, + maxSignals: DEFAULT_MAX_SIGNALS, }; const DEFAULT_INTERVAL = '5m'; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/asset_criticality_file_uploader.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/asset_criticality_file_uploader.tsx index 0acd1f831ca7..9c76c1e5f508 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/asset_criticality_file_uploader.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/asset_criticality_file_uploader.tsx @@ -16,6 +16,7 @@ import { AssetCriticalityResultStep } from './components/result_step'; import { useEntityAnalyticsRoutes } from '../../api/api'; import { useFileValidation, useNavigationSteps } from './hooks'; import type { OnCompleteParams } from './types'; +import { EntityEventTypes } from '../../../common/lib/telemetry'; export const AssetCriticalityFileUploader: React.FC = () => { const [state, dispatch] = useReducer(reducer, INITIAL_STATE); @@ -24,7 +25,7 @@ export const AssetCriticalityFileUploader: React.FC = () => { const onValidationComplete = useCallback( ({ validatedFile, processingStartTime, processingEndTime, tookMs }: OnCompleteParams) => { - telemetry.reportAssetCriticalityCsvPreviewGenerated({ + telemetry.reportEvent(EntityEventTypes.AssetCriticalityCsvPreviewGenerated, { file: { size: validatedFile.size, }, diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/result_step.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/result_step.tsx index 07629b2c6e0b..7026525f4578 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/result_step.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/result_step.tsx @@ -7,7 +7,6 @@ import { EuiButtonEmpty, - EuiButton, EuiCallOut, EuiCodeBlock, EuiFlexGroup, @@ -19,6 +18,7 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; import { SecurityPageName } from '@kbn/deeplinks-security'; +import { SecuritySolutionLinkButton } from '../../../../common/components/links'; import type { BulkUpsertAssetCriticalityRecordsResponse } from '../../../../../common/api/entity_analytics'; import { buildAnnotationsFromError } from '../helpers'; import { ScheduleRiskEngineCallout } from './schedule_risk_engine_callout'; @@ -75,14 +75,14 @@ export const AssetCriticalityResultStep: React.FC<{ id="xpack.securitySolution.entityAnalytics.assetCriticalityResultStep.successMessage" /> - + { } - + diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/validation_step.test.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/validation_step.test.tsx index ca1dcfb6e7f4..f3200b5c6ee4 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/validation_step.test.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/validation_step.test.tsx @@ -20,7 +20,7 @@ jest.mock('../../../../common/lib/kibana/kibana_react', () => ({ useKibana: () => ({ services: { telemetry: { - reportAssetCriticalityCsvImported: jest.fn(), + reportEvent: jest.fn(), }, }, }), diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/validation_step.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/validation_step.tsx index 538e19f4d5fd..c4dadc756c15 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/validation_step.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/validation_step.tsx @@ -23,6 +23,7 @@ import { downloadBlob } from '../../../../common/utils/download_blob'; import { useKibana } from '../../../../common/lib/kibana/kibana_react'; import type { ValidatedFile } from '../types'; import { buildAnnotationsFromError } from '../helpers'; +import { EntityEventTypes } from '../../../../common/lib/telemetry'; export interface AssetCriticalityValidationStepProps { validatedFile: ValidatedFile; @@ -42,7 +43,7 @@ export const AssetCriticalityValidationStep: React.FC { - telemetry.reportAssetCriticalityCsvImported({ + telemetry.reportEvent(EntityEventTypes.AssetCriticalityCsvImported, { file: { size: fileSize, }, diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/hooks.ts b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/hooks.ts index 107ba6348ac7..0472f5002fcb 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/hooks.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/hooks.ts @@ -17,6 +17,7 @@ import { useKibana } from '../../../common/lib/kibana'; import type { OnCompleteParams } from './types'; import type { ReducerState } from './reducer'; import { getStepStatus, isValidationStep } from './helpers'; +import { EntityEventTypes } from '../../../common/lib/telemetry'; interface UseFileChangeCbParams { onError: (errorMessage: string, file: File) => void; @@ -35,7 +36,7 @@ export const useFileValidation = ({ onError, onComplete }: UseFileChangeCbParams }, file: File ) => { - telemetry.reportAssetCriticalityFileSelected({ + telemetry.reportEvent(EntityEventTypes.AssetCriticalityFileSelected, { valid: false, errorCode: error.code, file: { @@ -62,7 +63,7 @@ export const useFileValidation = ({ onError, onComplete }: UseFileChangeCbParams return; } - telemetry.reportAssetCriticalityFileSelected({ + telemetry.reportEvent(EntityEventTypes.AssetCriticalityFileSelected, { valid: true, file: { size: file.size, diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_anomalies/anomalies_count_link.test.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_anomalies/anomalies_count_link.test.tsx index 8400578b85c4..32234547ca62 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_anomalies/anomalies_count_link.test.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_anomalies/anomalies_count_link.test.tsx @@ -10,6 +10,7 @@ import { AnomalyEntity } from '../../../common/components/ml/anomaly/use_anomali import { createTelemetryServiceMock } from '../../../common/lib/telemetry/telemetry_service.mock'; import { TestProviders } from '../../../common/mock'; import { AnomaliesCountLink } from './anomalies_count_link'; +import { EntityEventTypes } from '../../../common/lib/telemetry'; const mockedTelemetry = createTelemetryServiceMock(); jest.mock('../../../common/lib/kibana', () => { @@ -37,6 +38,9 @@ describe('AnomaliesCountLink', () => { fireEvent.click(getByRole('button')); - expect(mockedTelemetry.reportAnomaliesCountClicked).toHaveBeenLastCalledWith({ jobId, count }); + expect(mockedTelemetry.reportEvent).toHaveBeenLastCalledWith( + EntityEventTypes.AnomaliesCountClicked, + { jobId, count } + ); }); }); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_anomalies/anomalies_count_link.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_anomalies/anomalies_count_link.tsx index bb32564acb1b..6068d0ece667 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_anomalies/anomalies_count_link.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_anomalies/anomalies_count_link.tsx @@ -15,6 +15,7 @@ import { HostsType } from '../../../explore/hosts/store/model'; import { UsersType } from '../../../explore/users/store/model'; import { useKibana } from '../../../common/lib/kibana'; +import { EntityEventTypes } from '../../../common/lib/telemetry'; export const AnomaliesCountLink = ({ count, @@ -36,7 +37,7 @@ export const AnomaliesCountLink = ({ const onClick = useCallback(() => { if (!jobId) return; - telemetry.reportAnomaliesCountClicked({ + telemetry.reportEvent(EntityEventTypes.AnomaliesCountClicked, { jobId, count, }); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_risk_score/columns.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_risk_score/columns.tsx index e6ac30f15c5b..9459953b6d1d 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_risk_score/columns.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_risk_score/columns.tsx @@ -30,6 +30,7 @@ import { SecurityCellActionType, } from '../../../common/components/cell_actions'; import { FormattedRelativePreferenceDate } from '../../../common/components/formatted_date'; +import { formatRiskScore } from '../../common'; type HostRiskScoreColumns = Array>; @@ -128,7 +129,7 @@ export const getRiskScoreColumns = ( if (riskScore != null) { return ( - {Math.round(riskScore)} + {formatRiskScore(riskScore)} ); } diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_risk_score/index.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_risk_score/index.tsx index ffa1afffdf21..08ce79cc74c1 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_risk_score/index.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_risk_score/index.tsx @@ -38,6 +38,7 @@ import { useRiskScore } from '../../api/hooks/use_risk_score'; import { UserPanelKey } from '../../../flyout/entity_details/user_right'; import { RiskEnginePrivilegesCallOut } from '../risk_engine_privileges_callout'; import { useMissingRiskEnginePrivileges } from '../../hooks/use_missing_risk_engine_privileges'; +import { EntityEventTypes } from '../../../common/lib/telemetry'; export const ENTITY_RISK_SCORE_TABLE_ID = 'entity-risk-score-table'; @@ -51,7 +52,7 @@ const EntityAnalyticsRiskScoresComponent = ({ riskEntity }: { riskEntity: RiskSc const openEntityOnAlertsPage = useCallback( (entityName: string) => { - telemetry.reportEntityAlertsClicked({ entity: riskEntity }); + telemetry.reportEvent(EntityEventTypes.EntityAlertsClicked, { entity: riskEntity }); openAlertsPageWithFilters([ { title: getRiskEntityTranslation(riskEntity), diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/hooks/use_risk_input_actions.ts b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/hooks/use_risk_input_actions.ts index b12f82128c82..a8a7f60e075a 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/hooks/use_risk_input_actions.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_details_flyout/hooks/use_risk_input_actions.ts @@ -17,6 +17,7 @@ import { SourcererScopeName } from '../../../../sourcerer/store/model'; import { useAddBulkToTimelineAction } from '../../../../detections/components/alerts_table/timeline_actions/use_add_bulk_to_timeline'; import { useKibana } from '../../../../common/lib/kibana/kibana_react'; import type { InputAlert } from '../../../hooks/use_risk_contributing_alerts'; +import { EntityEventTypes } from '../../../../common/lib/telemetry'; /** * The returned actions only support alerts risk inputs. @@ -61,7 +62,7 @@ export const useRiskInputActions = (inputs: InputAlert[], closePopover: () => vo }, addToNewTimeline: () => { - telemetry.reportAddRiskInputToTimelineClicked({ + telemetry.reportEvent(EntityEventTypes.AddRiskInputToTimelineClicked, { quantity: inputs.length, }); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/enablement_modal.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/enablement_modal.tsx index 974bdddc831e..6c2528620eb4 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/enablement_modal.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/enablement_modal.tsx @@ -72,20 +72,13 @@ export const EntityStoreEnablementModal: React.FC - - - - { fireEvent.click(columnHeader); expect(mockUseEntitiesListQuery).toHaveBeenCalledWith( expect.objectContaining({ - sortField: 'entity.name.text', + sortField: 'entity.name', sortOrder: 'asc', }) ); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entities_list_columns.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entities_list_columns.tsx index 974a80454ee2..1da79d3d2cd0 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entities_list_columns.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entities_list_columns.tsx @@ -21,6 +21,7 @@ import { type CriticalityLevels } from '../../../../../common/constants'; import { ENTITIES_LIST_TABLE_ID } from '../constants'; import { isUserEntity, sourceFieldToText } from '../helpers'; import { CRITICALITY_LEVEL_TITLE } from '../../asset_criticality/translations'; +import { formatRiskScore } from '../../../common'; export type EntitiesListColumns = [ Columns, @@ -79,7 +80,7 @@ export const useEntitiesListColumns = (): EntitiesListColumns => { width: '5%', }, { - field: 'entity.name.text', + field: 'entity.name', name: ( { if (riskScore != null) { return ( - {Math.round(riskScore)} + {formatRiskScore(riskScore)} ); } diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_store.ts b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_store.ts index 21e73241451e..8aefbe2b44af 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_store.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_store.ts @@ -17,6 +17,7 @@ import type { } from '../../../../../common/api/entity_analytics'; import { useEntityStoreRoutes } from '../../../api/entity_store'; import { ENTITY_STORE_ENGINE_STATUS, useEntityEngineStatus } from './use_entity_engine_status'; +import { EntityEventTypes } from '../../../../common/lib/telemetry'; const ENTITY_STORE_ENABLEMENT_INIT = 'ENTITY_STORE_ENABLEMENT_INIT'; @@ -49,7 +50,7 @@ export const useEntityStoreEnablement = () => { }); const enable = useCallback(() => { - telemetry?.reportEntityStoreInit({ + telemetry?.reportEvent(EntityEventTypes.EntityStoreDashboardInitButtonClicked, { timestamp: new Date().toISOString(), }); return initialize().then(() => setPolling(true)); @@ -76,7 +77,7 @@ export const useInitEntityEngineMutation = (options?: UseMutationOptions<{}>) => const { initEntityStore } = useEntityStoreRoutes(); return useMutation( () => { - telemetry?.reportEntityStoreEnablement({ + telemetry?.reportEvent(EntityEventTypes.EntityStoreEnablementToggleClicked, { timestamp: new Date().toISOString(), action: 'start', }); @@ -106,7 +107,7 @@ export const useStopEntityEngineMutation = (options?: UseMutationOptions<{}>) => const { stopEntityStore } = useEntityStoreRoutes(); return useMutation( () => { - telemetry?.reportEntityStoreEnablement({ + telemetry?.reportEvent(EntityEventTypes.EntityStoreEnablementToggleClicked, { timestamp: new Date().toISOString(), action: 'stop', }); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/host_risk_score_table/columns.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/host_risk_score_table/columns.tsx index e1509a03a9a9..ac8558973633 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/host_risk_score_table/columns.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/host_risk_score_table/columns.tsx @@ -23,6 +23,7 @@ import { RiskScoreLevel } from '../severity/common'; import { ENTITY_RISK_LEVEL } from '../risk_score/translations'; import { CELL_ACTIONS_TELEMETRY } from '../risk_score/constants'; import { FormattedRelativePreferenceDate } from '../../../common/components/formatted_date'; +import { formatRiskScore } from '../../common'; export const getHostRiskScoreColumns = ({ dispatchSeverityUpdate, @@ -82,7 +83,7 @@ export const getHostRiskScoreColumns = ({ if (riskScore != null) { return ( - {Math.round(riskScore)} + {formatRiskScore(riskScore)} ); } diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.tsx index 2dec7d07ce6e..0c42543a7f91 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.tsx @@ -43,6 +43,7 @@ import { LENS_VISUALIZATION_MIN_WIDTH, SUMMARY_TABLE_MIN_WIDTH, } from './common'; +import { EntityEventTypes } from '../../../common/lib/telemetry'; export interface RiskSummaryProps { riskScoreData: RiskScoreState; @@ -84,7 +85,7 @@ const FlyoutRiskSummaryComponent = ({ (isOpen: boolean) => { const entity = isUserRiskData(riskData) ? 'user' : 'host'; - telemetry.reportToggleRiskSummaryClicked({ + telemetry.reportEvent(EntityEventTypes.ToggleRiskSummaryClicked, { entity, action: isOpen ? 'show' : 'hide', }); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/severity/severity_filter.test.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/severity/severity_filter.test.tsx index 8adbc2c7578d..c50d5a1be774 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/severity/severity_filter.test.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/severity/severity_filter.test.tsx @@ -24,7 +24,7 @@ jest.mock('../../../common/lib/kibana', () => { describe('SeverityFilter', () => { beforeEach(() => { - mockedTelemetry.reportEntityRiskFiltered.mockClear(); + mockedTelemetry.reportEvent.mockClear(); }); it('sends telemetry when selecting a classification', () => { @@ -38,7 +38,7 @@ describe('SeverityFilter', () => { fireEvent.click(getByTestId('risk-filter-item-Unknown')); - expect(mockedTelemetry.reportEntityRiskFiltered).toHaveBeenCalledTimes(1); + expect(mockedTelemetry.reportEvent).toHaveBeenCalledTimes(1); }); it('does not send telemetry when deselecting a classification', () => { @@ -61,6 +61,6 @@ describe('SeverityFilter', () => { fireEvent.click(getByTestId('risk-filter-popoverButton')); fireEvent.click(getByTestId('risk-filter-item-Unknown')); - expect(mockedTelemetry.reportEntityRiskFiltered).toHaveBeenCalledTimes(0); + expect(mockedTelemetry.reportEvent).toHaveBeenCalledTimes(0); }); }); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/severity/severity_filter.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/severity/severity_filter.tsx index 6aa150e40afa..6da522658894 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/severity/severity_filter.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/severity/severity_filter.tsx @@ -13,6 +13,7 @@ import type { RiskScoreEntity, RiskSeverity } from '../../../../common/search_st import { RiskScoreLevel } from './common'; import { ENTITY_RISK_LEVEL } from '../risk_score/translations'; import { useKibana } from '../../../common/lib/kibana'; +import { EntityEventTypes } from '../../../common/lib/telemetry'; export interface SeverityFilterProps { riskEntity?: RiskScoreEntity; @@ -35,7 +36,7 @@ export const SeverityFilter: React.FC = ({ >( (newSelection, changedSeverity, changedStatus) => { if (changedStatus === 'on') { - telemetry.reportEntityRiskFiltered({ + telemetry.reportEvent(EntityEventTypes.EntityRiskFiltered, { entity: riskEntity, selectedSeverity: changedSeverity, }); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/user_risk_score_table/columns.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/user_risk_score_table/columns.tsx index 49eaf7b3cc26..0cb7960ecabb 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/user_risk_score_table/columns.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/user_risk_score_table/columns.tsx @@ -24,6 +24,7 @@ import { UsersTableType } from '../../../explore/users/store/model'; import { ENTITY_RISK_LEVEL } from '../risk_score/translations'; import { CELL_ACTIONS_TELEMETRY } from '../risk_score/constants'; import { FormattedRelativePreferenceDate } from '../../../common/components/formatted_date'; +import { formatRiskScore } from '../../common'; export const getUserRiskScoreColumns = ({ dispatchSeverityUpdate, @@ -85,7 +86,7 @@ export const getUserRiskScoreColumns = ({ if (riskScore != null) { return ( - {Math.round(riskScore)} + {formatRiskScore(riskScore)} ); } diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx index c315e991d9f0..e3fd2fef8bc6 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx @@ -71,6 +71,7 @@ import type { NarrowDateRange } from '../../../../common/components/ml/types'; import { MisconfigurationsInsight } from '../../shared/components/misconfiguration_insight'; import { VulnerabilitiesInsight } from '../../shared/components/vulnerabilities_insight'; import { AlertCountInsight } from '../../shared/components/alert_count_insight'; +import { DocumentEventTypes } from '../../../../common/lib/telemetry'; const HOST_DETAILS_ID = 'entities-hosts-details'; const RELATED_USERS_ID = 'entities-hosts-related-users'; @@ -134,7 +135,7 @@ export const HostDetails: React.FC = ({ hostName, timestamp, s banner: HOST_PREVIEW_BANNER, }, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: scopeId, panel: 'preview', }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.test.tsx index db9eb7bdfb3a..48f7a1fbce0a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.test.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; -import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { CORRELATIONS_DETAILS_CASES_SECTION_TABLE_TEST_ID, @@ -19,13 +18,26 @@ import { EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, } from '../../../shared/components/test_ids'; +import { SecurityPageName } from '@kbn/deeplinks-security'; +import { TestProviders } from '../../../../common/mock'; +import { APP_UI_ID } from '../../../../../common'; jest.mock('../../shared/hooks/use_fetch_related_cases'); -jest.mock('../../../../common/components/links', () => ({ - CaseDetailsLink: jest - .fn() - .mockImplementation(({ title }) => <>{``}), -})); + +const mockNavigateToApp = jest.fn(); +jest.mock('../../../../common/lib/kibana', () => { + const original = jest.requireActual('../../../../common/lib/kibana'); + return { + ...original, + useKibana: () => ({ + services: { + application: { + navigateToApp: mockNavigateToApp, + }, + }, + }), + }; +}); const eventId = 'eventId'; @@ -41,13 +53,53 @@ const TITLE_TEXT = EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID( const renderRelatedCases = () => render( - + - + ); describe('', () => { it('should render many related cases correctly', () => { + (useFetchRelatedCases as jest.Mock).mockReturnValue({ + loading: false, + error: false, + data: [ + { + id: 'id1', + title: 'title1', + description: 'description1', + status: 'open', + }, + { + id: 'id2', + title: 'title2', + description: 'description2', + status: 'in-progress', + }, + { + id: 'id3', + title: 'title3', + description: 'description3', + status: 'closed', + }, + ], + dataCount: 3, + }); + + const { getByTestId, getByText } = renderRelatedCases(); + expect(getByTestId(TOGGLE_ICON)).toBeInTheDocument(); + expect(getByTestId(TITLE_ICON)).toBeInTheDocument(); + expect(getByTestId(TITLE_TEXT)).toHaveTextContent('3 related cases'); + expect(getByTestId(CORRELATIONS_DETAILS_CASES_SECTION_TABLE_TEST_ID)).toBeInTheDocument(); + expect(getByText('title1')).toBeInTheDocument(); + expect(getByText('open')).toBeInTheDocument(); + expect(getByText('title2')).toBeInTheDocument(); + expect(getByText('in-progress')).toBeInTheDocument(); + expect(getByText('title3')).toBeInTheDocument(); + expect(getByText('closed')).toBeInTheDocument(); + }); + + it('should open new tab when clicking on the case link', () => { (useFetchRelatedCases as jest.Mock).mockReturnValue({ loading: false, error: false, @@ -63,10 +115,12 @@ describe('', () => { }); const { getByTestId } = renderRelatedCases(); - expect(getByTestId(TOGGLE_ICON)).toBeInTheDocument(); - expect(getByTestId(TITLE_ICON)).toBeInTheDocument(); - expect(getByTestId(TITLE_TEXT)).toHaveTextContent('1 related case'); - expect(getByTestId(CORRELATIONS_DETAILS_CASES_SECTION_TABLE_TEST_ID)).toBeInTheDocument(); + getByTestId('case-details-link').click(); + expect(mockNavigateToApp).toHaveBeenCalledWith(APP_UI_ID, { + deepLinkId: SecurityPageName.case, + path: '/id', + openInNewTab: true, + }); }); it('should render null if error', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.tsx index 13df33a2deb1..0ce04507b9b0 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.tsx @@ -7,9 +7,10 @@ import React, { useMemo } from 'react'; import type { EuiBasicTableColumn } from '@elastic/eui'; -import { EuiInMemoryTable } from '@elastic/eui'; +import { EuiIcon, EuiInMemoryTable } from '@elastic/eui'; import type { RelatedCase } from '@kbn/cases-plugin/common'; import { FormattedMessage } from '@kbn/i18n-react'; +import { css } from '@emotion/react'; import { CellTooltipWrapper } from '../../shared/components/cell_tooltip_wrapper'; import { CaseDetailsLink } from '../../../../common/components/links'; import { @@ -20,6 +21,10 @@ import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases import { ExpandablePanel } from '../../../shared/components/expandable_panel'; const ICON = 'warning'; +const EXPAND_PROPERTIES = { + expandable: true, + expandedOnFirstRender: true, +}; const getColumns: (data: RelatedCase[]) => Array> = (data) => [ { @@ -30,16 +35,21 @@ const getColumns: (data: RelatedCase[]) => Array ), - render: (value: string, caseData: RelatedCase) => { - const index = data.findIndex((d) => d.id === caseData.id); - return ( - - - {caseData.title} - - - ); - }, + render: (_: string, caseData: RelatedCase) => ( + + + {caseData.title} + + + + ), }, { field: 'status', @@ -62,33 +72,38 @@ export interface RelatedCasesProps { } /** - * + * Show related cases in an expandable panel with a table */ export const RelatedCases: React.FC = ({ eventId }) => { const { loading, error, data, dataCount } = useFetchRelatedCases({ eventId }); const columns = useMemo(() => getColumns(data), [data]); + const title = useMemo( + () => ( + + ), + [dataCount] + ); + const header = useMemo( + () => ({ + title, + iconType: ICON, + }), + [title] + ); + if (error) { return null; } return ( - ), - iconType: ICON, - }} - content={{ error }} - expand={{ - expandable: true, - expandedOnFirstRender: true, - }} + header={header} + expand={EXPAND_PROPERTIES} data-test-subj={CORRELATIONS_DETAILS_CASES_SECTION_TEST_ID} > { isPreviewMode: true, }, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: scopeId, panel: 'preview', }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx index 2f98c641b595..e88cbb54f947 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx @@ -69,6 +69,7 @@ import { PreviewLink } from '../../../shared/components/preview_link'; import type { NarrowDateRange } from '../../../../common/components/ml/types'; import { MisconfigurationsInsight } from '../../shared/components/misconfiguration_insight'; import { AlertCountInsight } from '../../shared/components/alert_count_insight'; +import { DocumentEventTypes } from '../../../../common/lib/telemetry'; const USER_DETAILS_ID = 'entities-users-details'; const RELATED_HOSTS_ID = 'entities-users-related-hosts'; @@ -133,7 +134,7 @@ export const UserDetails: React.FC = ({ userName, timestamp, s banner: USER_PREVIEW_BANNER, }, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: scopeId, panel: 'preview', }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx index 56375426c5f6..6dcf9da06d2b 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/index.tsx @@ -22,6 +22,7 @@ import { getField } from '../shared/utils'; import { EventKind } from '../shared/constants/event_kinds'; import { useDocumentDetailsContext } from '../shared/context'; import type { DocumentDetailsProps } from '../shared/types'; +import { DocumentEventTypes } from '../../../common/lib/telemetry/types'; export type LeftPanelPaths = 'visualize' | 'insights' | 'investigation' | 'response' | 'notes'; export const LeftPanelVisualizeTab: LeftPanelPaths = 'visualize'; @@ -75,7 +76,7 @@ export const LeftPanel: FC> = memo(({ path }) => { scopeId, }, }); - telemetry.reportDetailsFlyoutTabClicked({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutTabClicked, { location: scopeId, panel: 'left', tabId, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/insights_tab.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/insights_tab.tsx index 3917de03e2e3..0982e10485ba 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/insights_tab.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/tabs/insights_tab.tsx @@ -31,6 +31,7 @@ import { PREVALENCE_TAB_ID, PrevalenceDetails } from '../components/prevalence_d import { CORRELATIONS_TAB_ID, CorrelationsDetails } from '../components/correlations_details'; import { getField } from '../../shared/utils'; import { EventKind } from '../../shared/constants/event_kinds'; +import { DocumentEventTypes } from '../../../../common/lib/telemetry'; const ENTITIES_TAB_ID = 'entity'; @@ -113,7 +114,7 @@ export const InsightsTab = memo(() => { scopeId, }, }); - telemetry.reportDetailsFlyoutTabClicked({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutTabClicked, { location: scopeId, panel: 'left', tabId: optionId, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/preview/footer.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/preview/footer.tsx index 020133288867..b2df6c096e27 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/preview/footer.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/preview/footer.tsx @@ -16,6 +16,7 @@ import { DocumentDetailsRightPanelKey } from '../shared/constants/panel_keys'; import { useDocumentDetailsContext } from '../shared/context'; import { PREVIEW_FOOTER_TEST_ID, PREVIEW_FOOTER_LINK_TEST_ID } from './test_ids'; import { useKibana } from '../../../common/lib/kibana'; +import { DocumentEventTypes } from '../../../common/lib/telemetry'; /** * Footer at the bottom of preview panel with a link to open document details flyout @@ -41,7 +42,7 @@ export const PreviewPanelFooter = () => { }, }, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: scopeId, panel: 'right', }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_description.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_description.tsx index 2d2dfddbbbab..91d5059e5d60 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_description.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_description.tsx @@ -22,6 +22,7 @@ import { RULE_SUMMARY_BUTTON_TEST_ID, } from './test_ids'; import { RULE_PREVIEW_BANNER, RulePreviewPanelKey } from '../../../rule_details/right'; +import { DocumentEventTypes } from '../../../../common/lib/telemetry'; /** * Displays the rule description of a signal document. @@ -42,7 +43,7 @@ export const AlertDescription: FC = () => { isPreviewMode: true, }, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: scopeId, panel: 'preview', }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx index c9d8606cf934..ff8961a08780 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx @@ -127,7 +127,7 @@ describe('', () => { jest.mocked(useTourContext).mockReturnValue({ hidden: false, setAllTourStepsHidden: jest.fn(), - activeStep: AlertsCasesTourSteps.viewCase, + activeStep: AlertsCasesTourSteps.submitCase, endTourStep: jest.fn(), incrementStep: jest.fn(), isTourShown: jest.fn(), diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx index 9ba55f0d041f..4043230d5269 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx @@ -73,7 +73,7 @@ export const CorrelationsOverview: React.FC = () => { }, [eventId, openLeftPanel, indexName, scopeId]); useEffect(() => { - if (isTourShown(SecurityStepId.alertsCases) && activeStep === AlertsCasesTourSteps.viewCase) { + if (isTourShown(SecurityStepId.alertsCases) && activeStep === AlertsCasesTourSteps.createCase) { goToCorrelationsTab(); } }, [activeStep, goToCorrelationsTab, isTourShown]); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/graph_preview_container.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/graph_preview_container.tsx index be6559336459..af9e8dca1f24 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/graph_preview_container.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/graph_preview_container.tsx @@ -32,7 +32,6 @@ export const GraphPreviewContainer: React.FC = () => { const graphFetchQuery = useFetchGraphData({ req: { query: { - actorIds: [], eventIds, start: DEFAULT_FROM, end: DEFAULT_TO, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_section.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_section.test.tsx index 96dff8150e65..c06481c6b281 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_section.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_section.test.tsx @@ -171,7 +171,7 @@ describe('', () => { it('should render the component expanded if guided onboarding tour is shown', () => { (useExpandSection as jest.Mock).mockReturnValue(false); - mockUseTourContext.mockReturnValue({ activeStep: 7, isTourShown: jest.fn(() => true) }); + mockUseTourContext.mockReturnValue({ activeStep: 5, isTourShown: jest.fn(() => true) }); const contextValue = { eventId: 'some_Id', diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_section.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_section.tsx index 19c75a77cbab..c2d71ee37baa 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_section.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_section.tsx @@ -35,7 +35,7 @@ export const InsightsSection = memo(() => { const { activeStep, isTourShown } = useTourContext(); const isGuidedOnboardingTourShown = - isTourShown(SecurityStepId.alertsCases) && activeStep === AlertsCasesTourSteps.viewCase; + isTourShown(SecurityStepId.alertsCases) && activeStep === AlertsCasesTourSteps.createCase; const expanded = useExpandSection({ title: KEY, defaultValue: false }) || isGuidedOnboardingTourShown; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.test.tsx index f70cd2aae3e8..023b0202ecb6 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.test.tsx @@ -23,6 +23,7 @@ import type { Note } from '../../../../../common/api/timeline'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { LeftPanelNotesTab } from '../../left'; +import { getEmptyValue } from '../../../../common/components/empty_value'; jest.mock('@kbn/expandable-flyout'); @@ -43,6 +44,10 @@ jest.mock('react-redux', () => { }); describe('', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + it('should render loading spinner', () => { (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: jest.fn() }); @@ -99,6 +104,34 @@ describe('', () => { }); }); + it('should disabled the Add note button if in preview mode', () => { + const contextValue = { + ...mockContextValue, + isPreviewMode: true, + }; + + const mockOpenLeftPanel = jest.fn(); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + + const { getByTestId } = render( + + + + + + ); + + expect(mockDispatch).not.toHaveBeenCalled(); + + const button = getByTestId(NOTES_ADD_NOTE_BUTTON_TEST_ID); + expect(button).toBeInTheDocument(); + expect(button).toBeDisabled(); + + button.click(); + + expect(mockOpenLeftPanel).not.toHaveBeenCalled(); + }); + it('should render number of notes and plus button', () => { const mockOpenLeftPanel = jest.fn(); (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); @@ -135,6 +168,38 @@ describe('', () => { }); }); + it('should disable the plus button if in preview mode', () => { + const mockOpenLeftPanel = jest.fn(); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + + const contextValue = { + ...mockContextValue, + eventId: '1', + isPreviewMode: true, + }; + + const { getByTestId } = render( + + + + + + ); + + expect(getByTestId(NOTES_COUNT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(NOTES_COUNT_TEST_ID)).toHaveTextContent('1'); + + expect(mockDispatch).not.toHaveBeenCalled(); + + const button = getByTestId(NOTES_ADD_NOTE_ICON_BUTTON_TEST_ID); + + expect(button).toBeInTheDocument(); + button.click(); + expect(button).toBeDisabled(); + + expect(mockOpenLeftPanel).not.toHaveBeenCalled(); + }); + it('should render number of notes in scientific notation for big numbers', () => { const createMockNote = (noteId: string): Note => ({ eventId: '1', // should be a valid id based on mockTimelineData @@ -180,6 +245,30 @@ describe('', () => { expect(getByTestId(NOTES_COUNT_TEST_ID)).toHaveTextContent('1k'); }); + it('should show a - when in rule creation workflow', () => { + const contextValue = { + ...mockContextValue, + isPreview: true, + }; + + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: jest.fn() }); + + const { getByText, queryByTestId } = render( + + + + + + ); + + expect(mockDispatch).not.toHaveBeenCalled(); + + expect(queryByTestId(NOTES_ADD_NOTE_ICON_BUTTON_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(NOTES_ADD_NOTE_BUTTON_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(NOTES_COUNT_TEST_ID)).not.toBeInTheDocument(); + expect(getByText(getEmptyValue())).toBeInTheDocument(); + }); + it('should render toast error', () => { const store = createMockStore({ ...mockGlobalState, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.tsx index a981a16117a6..b0e2008c0410 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.tsx @@ -19,6 +19,7 @@ import { } from '@elastic/eui'; import { css } from '@emotion/react'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { getEmptyTagValue } from '../../../../common/components/empty_value'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { FormattedCount } from '../../../../common/components/formatted_number'; import { useDocumentDetailsContext } from '../../shared/context'; @@ -61,7 +62,7 @@ export const ADD_NOTE_BUTTON = i18n.translate( export const Notes = memo(() => { const { euiTheme } = useEuiTheme(); const dispatch = useDispatch(); - const { eventId, indexName, scopeId } = useDocumentDetailsContext(); + const { eventId, indexName, scopeId, isPreview, isPreviewMode } = useDocumentDetailsContext(); const { addError: addErrorToast } = useAppToasts(); const { openLeftPanel } = useExpandableFlyoutApi(); @@ -80,8 +81,11 @@ export const Notes = memo(() => { ); useEffect(() => { - dispatch(fetchNotesByDocumentIds({ documentIds: [eventId] })); - }, [dispatch, eventId]); + // only fetch notes if we are not in a preview panel, or not in a rule preview workflow + if (!isPreviewMode && !isPreview) { + dispatch(fetchNotesByDocumentIds({ documentIds: [eventId] })); + } + }, [dispatch, eventId, isPreview, isPreviewMode]); const fetchStatus = useSelector((state: State) => selectFetchNotesByDocumentIdsStatus(state)); const fetchError = useSelector((state: State) => selectFetchNotesByDocumentIdsError(state)); @@ -107,37 +111,45 @@ export const Notes = memo(() => { } data-test-subj={NOTES_TITLE_TEST_ID} > - {fetchStatus === ReqStatus.Loading ? ( - + {isPreview ? ( + getEmptyTagValue() ) : ( <> - {notes.length === 0 ? ( - - {ADD_NOTE_BUTTON} - + {fetchStatus === ReqStatus.Loading ? ( + ) : ( - - - - - - + {notes.length === 0 ? ( + - - + data-test-subj={NOTES_ADD_NOTE_BUTTON_TEST_ID} + > + {ADD_NOTE_BUTTON} + + ) : ( + + + + + + + + + )} + )} )} diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.tsx index c4b0e6e26a82..fc6db84ad439 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.tsx @@ -22,6 +22,7 @@ import { } from './test_ids'; import { useBasicDataFromDetailsData } from '../../shared/hooks/use_basic_data_from_details_data'; import { useDocumentDetailsContext } from '../../shared/context'; +import { DocumentEventTypes } from '../../../../common/lib/telemetry'; export const ALERT_REASON_BANNER = { title: i18n.translate( @@ -55,7 +56,7 @@ export const Reason: FC = () => { banner: ALERT_REASON_BANNER, }, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: scopeId, panel: 'preview', }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_fetch_graph_data.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_fetch_graph_data.test.tsx new file mode 100644 index 000000000000..c22ec0caa82c --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_fetch_graph_data.test.tsx @@ -0,0 +1,89 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderHook } from '@testing-library/react-hooks'; +import { useFetchGraphData } from './use_fetch_graph_data'; + +const mockUseQuery = jest.fn(); + +jest.mock('@tanstack/react-query', () => { + return { + useQuery: (...args: unknown[]) => mockUseQuery(...args), + }; +}); + +describe('useFetchGraphData', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('Should pass default options when options are not provided', () => { + renderHook(() => { + return useFetchGraphData({ + req: { + query: { + eventIds: [], + start: '2021-09-01T00:00:00.000Z', + end: '2021-09-01T23:59:59.999Z', + }, + }, + }); + }); + + expect(mockUseQuery.mock.calls).toHaveLength(1); + expect(mockUseQuery.mock.calls[0][2]).toEqual({ + enabled: true, + refetchOnWindowFocus: true, + }); + }); + + it('Should should not be enabled when enabled set to false', () => { + renderHook(() => { + return useFetchGraphData({ + req: { + query: { + eventIds: [], + start: '2021-09-01T00:00:00.000Z', + end: '2021-09-01T23:59:59.999Z', + }, + }, + options: { + enabled: false, + }, + }); + }); + + expect(mockUseQuery.mock.calls).toHaveLength(1); + expect(mockUseQuery.mock.calls[0][2]).toEqual({ + enabled: false, + refetchOnWindowFocus: true, + }); + }); + + it('Should should not be refetchOnWindowFocus when refetchOnWindowFocus set to false', () => { + renderHook(() => { + return useFetchGraphData({ + req: { + query: { + eventIds: [], + start: '2021-09-01T00:00:00.000Z', + end: '2021-09-01T23:59:59.999Z', + }, + }, + options: { + refetchOnWindowFocus: false, + }, + }); + }); + + expect(mockUseQuery.mock.calls).toHaveLength(1); + expect(mockUseQuery.mock.calls[0][2]).toEqual({ + enabled: true, + refetchOnWindowFocus: false, + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_fetch_graph_data.ts b/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_fetch_graph_data.ts index 2304cfb8d4fd..9a0e270a9b2e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_fetch_graph_data.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_fetch_graph_data.ts @@ -10,6 +10,7 @@ import type { GraphRequest, GraphResponse, } from '@kbn/cloud-security-posture-common/types/graph/latest'; +import { useMemo } from 'react'; import { EVENT_GRAPH_VISUALIZATION_API } from '../../../../../common/constants'; import { useHttp } from '../../../../common/lib/kibana'; @@ -30,6 +31,11 @@ export interface UseFetchGraphDataParams { * Defaults to true. */ enabled?: boolean; + /** + * If true, the query will refetch on window focus. + * Defaults to true. + */ + refetchOnWindowFocus?: boolean; }; } @@ -61,18 +67,25 @@ export const useFetchGraphData = ({ req, options, }: UseFetchGraphDataParams): UseFetchGraphDataResult => { - const { actorIds, eventIds, start, end } = req.query; + const { eventIds, start, end, esQuery } = req.query; const http = useHttp(); + const QUERY_KEY = useMemo( + () => ['useFetchGraphData', eventIds, start, end, esQuery], + [end, esQuery, eventIds, start] + ); const { isLoading, isError, data } = useQuery( - ['useFetchGraphData', actorIds, eventIds, start, end], + QUERY_KEY, () => { return http.post(EVENT_GRAPH_VISUALIZATION_API, { version: '1', body: JSON.stringify(req), }); }, - options + { + enabled: options?.enabled ?? true, + refetchOnWindowFocus: options?.refetchOnWindowFocus ?? true, + } ); return { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/index.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/index.tsx index 56c24d956209..9d3262ce1ff3 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/index.tsx @@ -20,6 +20,7 @@ import { PanelContent } from './content'; import type { RightPanelTabType } from './tabs'; import { PanelFooter } from './footer'; import { useFlyoutIsExpandable } from './hooks/use_flyout_is_expandable'; +import { DocumentEventTypes } from '../../../common/lib/telemetry'; export type RightPanelPaths = 'overview' | 'table' | 'json'; @@ -53,7 +54,7 @@ export const RightPanel: FC> = memo(({ path }) => // saving which tab is currently selected in the right panel in local storage storage.set(FLYOUT_STORAGE_KEYS.RIGHT_PANEL_SELECTED_TABS, tabId); - telemetry.reportDetailsFlyoutTabClicked({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutTabClicked, { location: scopeId, panel: 'right', tabId, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/navigation.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/navigation.tsx index b4f12fbabf94..c3ee6a7d7a51 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/navigation.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/navigation.tsx @@ -13,6 +13,7 @@ import { HeaderActions } from './components/header_actions'; import { FlyoutNavigation } from '../../shared/components/flyout_navigation'; import { DocumentDetailsLeftPanelKey } from '../shared/constants/panel_keys'; import { useDocumentDetailsContext } from '../shared/context'; +import { DocumentEventTypes } from '../../../common/lib/telemetry'; interface PanelNavigationProps { /** @@ -35,7 +36,7 @@ export const PanelNavigation: FC = memo(({ flyoutIsExpanda scopeId, }, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: scopeId, panel: 'left', }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_navigate_to_analyzer.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_navigate_to_analyzer.tsx index 516a43332d29..a4539ed7e641 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_navigate_to_analyzer.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_navigate_to_analyzer.tsx @@ -19,6 +19,7 @@ import { } from '../constants/panel_keys'; import { Flyouts } from '../constants/flyouts'; import { isTimelineScope } from '../../../../helpers'; +import { DocumentEventTypes } from '../../../../common/lib/telemetry'; export interface UseNavigateToAnalyzerParams { /** @@ -107,7 +108,7 @@ export const useNavigateToAnalyzer = ({ if (isFlyoutOpen) { openLeftPanel(left); openPreviewPanel(preview); - telemetry.reportDetailsFlyoutTabClicked({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutTabClicked, { location: scopeId, panel: 'left', tabId: 'visualize', @@ -118,7 +119,7 @@ export const useNavigateToAnalyzer = ({ left, preview, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: scopeId, panel: 'left', }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_navigate_to_session_view.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_navigate_to_session_view.tsx index b8234321217e..f0b2733998c9 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_navigate_to_session_view.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_navigate_to_session_view.tsx @@ -12,6 +12,7 @@ import type { Maybe } from '@kbn/timelines-plugin/common/search_strategy/common' import { useKibana } from '../../../../common/lib/kibana'; import { SESSION_VIEW_ID } from '../../left/components/session_view'; import { DocumentDetailsLeftPanelKey, DocumentDetailsRightPanelKey } from '../constants/panel_keys'; +import { DocumentEventTypes } from '../../../../common/lib/telemetry'; export interface UseNavigateToSessionViewParams { /** @@ -83,7 +84,7 @@ export const useNavigateToSessionView = ({ const navigateToSessionView = useCallback(() => { if (isFlyoutOpen) { openLeftPanel(left); - telemetry.reportDetailsFlyoutTabClicked({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutTabClicked, { location: scopeId, panel: 'left', tabId: 'visualize', @@ -93,7 +94,7 @@ export const useNavigateToSessionView = ({ right, left, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: scopeId, panel: 'left', }); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx index adc54b58f75c..83fa75474a1c 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx @@ -35,6 +35,7 @@ import { useObservedHost } from './hooks/use_observed_host'; import { HostDetailsPanelKey } from '../host_details_left'; import { EntityDetailsLeftPanelTab } from '../shared/components/left_panel/left_panel_header'; import { HostPreviewPanelFooter } from '../host_preview/footer'; +import { EntityEventTypes } from '../../../common/lib/telemetry'; export interface HostPanelProps extends Record { contextID: string; @@ -130,7 +131,7 @@ export const HostPanel = ({ const openTabPanel = useCallback( (tab?: EntityDetailsLeftPanelTab) => { - telemetry.reportRiskInputsExpandedFlyoutOpened({ + telemetry.reportEvent(EntityEventTypes.RiskInputsExpandedFlyoutOpened, { entity: 'host', }); diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx index 3a60c06e3fae..42c8664b2ac0 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx @@ -33,6 +33,7 @@ import { UserDetailsPanelKey } from '../user_details_left'; import { useObservedUser } from './hooks/use_observed_user'; import { EntityDetailsLeftPanelTab } from '../shared/components/left_panel/left_panel_header'; import { UserPreviewPanelFooter } from '../user_preview/footer'; +import { EntityEventTypes } from '../../../common/lib/telemetry'; export interface UserPanelProps extends Record { contextID: string; @@ -123,7 +124,7 @@ export const UserPanel = ({ const { openLeftPanel } = useExpandableFlyoutApi(); const openPanelTab = useCallback( (tab?: EntityDetailsLeftPanelTab) => { - telemetry.reportRiskInputsExpandedFlyoutOpened({ + telemetry.reportEvent(EntityEventTypes.RiskInputsExpandedFlyoutOpened, { entity: 'user', }); diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/preview_link.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/preview_link.tsx index fc51a4e64e6c..b6a4ea33ba4b 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/preview_link.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/preview_link.tsx @@ -24,6 +24,7 @@ import { UserPreviewPanelKey } from '../../entity_details/user_right'; import { USER_PREVIEW_BANNER } from '../../document_details/right/components/user_entity_overview'; import { NetworkPanelKey, NETWORK_PREVIEW_BANNER } from '../../network_details'; import { RulePreviewPanelKey, RULE_PREVIEW_BANNER } from '../../rule_details/right'; +import { DocumentEventTypes } from '../../../common/lib/telemetry'; const PREVIEW_FIELDS = [HOST_NAME_FIELD_NAME, USER_NAME_FIELD_NAME, SIGNAL_RULE_NAME_FIELD_NAME]; @@ -133,7 +134,7 @@ export const PreviewLink: FC = ({ id: previewParams.id, params: previewParams.params, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: scopeId, panel: 'preview', }); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts index d11b7210713a..5ad7395efbe2 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts @@ -27,7 +27,8 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe('Response console', { tags: ['@ess', '@serverless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/172326 +describe.skip('Response console', { tags: ['@ess', '@serverless'] }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; let createdHost: CreateAndEnrollEndpointHostResponse; diff --git a/x-pack/plugins/security_solution/public/management/links.ts b/x-pack/plugins/security_solution/public/management/links.ts index 61cbc1a511c0..49049218d4dc 100644 --- a/x-pack/plugins/security_solution/public/management/links.ts +++ b/x-pack/plugins/security_solution/public/management/links.ts @@ -21,7 +21,6 @@ import { EVENT_FILTERS_PATH, HOST_ISOLATION_EXCEPTIONS_PATH, MANAGE_PATH, - NOTES_PATH, POLICIES_PATH, RESPONSE_ACTIONS_HISTORY_PATH, SecurityPageName, @@ -38,13 +37,13 @@ import { RESPONSE_ACTIONS_HISTORY, TRUSTED_APPLICATIONS, ENTITY_ANALYTICS_RISK_SCORE, - NOTES, ENTITY_STORE, } from '../app/translations'; import { licenseService } from '../common/hooks/use_license'; import type { LinkItem } from '../common/links/types'; import type { StartPlugins } from '../types'; import { cloudDefendLink } from '../cloud_defend/links'; +import { links as notesLink } from '../notes/links'; import { IconConsole } from '../common/icons/console'; import { IconShield } from '../common/icons/shield'; import { IconEndpoints } from '../common/icons/endpoints'; @@ -218,20 +217,7 @@ export const links: LinkItem = { hideTimeline: true, }, cloudDefendLink, - { - id: SecurityPageName.notes, - title: NOTES, - description: i18n.translate('xpack.securitySolution.appLinks.notesDescription', { - defaultMessage: - 'Oversee, revise, and revisit the notes attached to alerts, events and Timelines.', - }), - landingIcon: 'filebeatApp', - path: NOTES_PATH, - skipUrlState: true, - hideTimeline: true, - hideWhenExperimentalKey: 'securitySolutionNotesDisabled', - globalSearchDisabled: true, - }, + notesLink, ], }; diff --git a/x-pack/plugins/security_solution/public/notes/components/add_note.tsx b/x-pack/plugins/security_solution/public/notes/components/add_note.tsx index 78a84064467f..5d1ef2ce4d8e 100644 --- a/x-pack/plugins/security_solution/public/notes/components/add_note.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/add_note.tsx @@ -28,6 +28,7 @@ import { userClosedCreateErrorToast, } from '../store/notes.slice'; import { MarkdownEditor } from '../../common/components/markdown_editor'; +import { NotesEventTypes } from '../../common/lib/telemetry'; export const MARKDOWN_ARIA_LABEL = i18n.translate( 'xpack.securitySolution.notes.addNote.markdownAriaLabel', @@ -96,7 +97,7 @@ export const AddNote = memo( if (onNoteAdd) { onNoteAdd(); } - telemetry.reportAddNoteFromExpandableFlyoutClicked({ + telemetry.reportEvent(NotesEventTypes.AddNoteFromExpandableFlyoutClicked, { isRelatedToATimeline: timelineId != null, }); setEditorValue(''); diff --git a/x-pack/plugins/security_solution/public/notes/components/open_flyout_button.tsx b/x-pack/plugins/security_solution/public/notes/components/open_flyout_button.tsx index 85e9e24c6f26..65e6389fc2fd 100644 --- a/x-pack/plugins/security_solution/public/notes/components/open_flyout_button.tsx +++ b/x-pack/plugins/security_solution/public/notes/components/open_flyout_button.tsx @@ -16,6 +16,7 @@ import { useSourcererDataView } from '../../sourcerer/containers'; import { SourcererScopeName } from '../../sourcerer/store/model'; import { useKibana } from '../../common/lib/kibana'; import { DocumentDetailsRightPanelKey } from '../../flyout/document_details/shared/constants/panel_keys'; +import { DocumentEventTypes } from '../../common/lib/telemetry'; export const OPEN_FLYOUT_BUTTON = i18n.translate( 'xpack.securitySolution.notes.openFlyoutButtonLabel', @@ -61,7 +62,7 @@ export const OpenFlyoutButtonIcon = memo( }, }, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: timelineId, panel: 'right', }); diff --git a/x-pack/plugins/security_solution/public/notes/links.ts b/x-pack/plugins/security_solution/public/notes/links.ts index b09877e200fb..628904ae30c4 100644 --- a/x-pack/plugins/security_solution/public/notes/links.ts +++ b/x-pack/plugins/security_solution/public/notes/links.ts @@ -12,14 +12,15 @@ import type { LinkItem } from '../common/links/types'; export const links: LinkItem = { id: SecurityPageName.notes, - title: NOTES, path: NOTES_PATH, + title: NOTES, + description: i18n.translate('xpack.securitySolution.appLinks.notesDescription', { + defaultMessage: + 'Oversee, revise, and revisit the notes attached to alerts, events and Timelines.', + }), capabilities: [`${SERVER_APP_ID}.show`], - globalSearchKeywords: [ - i18n.translate('xpack.securitySolution.appLinks.notes', { - defaultMessage: 'Notes', - }), - ], - links: [], + landingIcon: 'filebeatApp', + skipUrlState: true, + hideTimeline: true, hideWhenExperimentalKey: 'securitySolutionNotesDisabled', }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_context.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_context.tsx index dda17e18c087..2a6597628a26 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_context.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_context.tsx @@ -9,6 +9,7 @@ import type { PropsWithChildren } from 'react'; import React, { createContext, useContext, useMemo } from 'react'; import { useKibana } from '../../common/lib/kibana/kibana_react'; import type { OnboardingCardId } from '../constants'; +import { OnboardingHubEventTypes } from '../../common/lib/telemetry'; export interface OnboardingContextValue { spaceId: string; @@ -26,19 +27,19 @@ export const OnboardingContextProvider: React.FC ({ spaceId, reportCardOpen: (cardId, { auto = false } = {}) => { - telemetry.reportOnboardingHubStepOpen({ + telemetry.reportEvent(OnboardingHubEventTypes.OnboardingHubStepOpen, { stepId: cardId, trigger: auto ? 'navigation' : 'click', }); }, reportCardComplete: (cardId, { auto = false } = {}) => { - telemetry.reportOnboardingHubStepFinished({ + telemetry.reportEvent(OnboardingHubEventTypes.OnboardingHubStepFinished, { stepId: cardId, trigger: auto ? 'auto_check' : 'click', }); }, reportCardLinkClicked: (cardId, linkId: string) => { - telemetry.reportOnboardingHubStepLinkClicked({ + telemetry.reportEvent(OnboardingHubEventTypes.OnboardingHubStepLinkClicked, { originStepId: cardId, stepLinkId: linkId, }); diff --git a/x-pack/plugins/security_solution/public/overview/pages/data_quality.test.tsx b/x-pack/plugins/security_solution/public/overview/pages/data_quality.test.tsx index e39e2abd2416..8b14fff8082c 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/data_quality.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/data_quality.test.tsx @@ -8,6 +8,7 @@ import { render, screen, waitFor } from '@testing-library/react'; import React from 'react'; import { MemoryRouter } from 'react-router-dom'; +import type { HttpFetchOptions } from '@kbn/core-http-browser'; import { useKibana as mockUseKibana } from '../../common/lib/kibana/__mocks__'; import { TestProviders } from '../../common/mock'; @@ -22,7 +23,17 @@ jest.mock('../../common/lib/kibana', () => { const mockKibanaServices = { get: () => ({ - http: { fetch: jest.fn() }, + http: { + fetch: jest.fn().mockImplementation((path: string, options: HttpFetchOptions) => { + if ( + path.startsWith('/internal/ecs_data_quality_dashboard/results_latest') && + options.method === 'GET' + ) { + return Promise.resolve([]); + } + return Promise.resolve(); + }), + }, }), }; diff --git a/x-pack/plugins/security_solution/public/overview/pages/data_quality.tsx b/x-pack/plugins/security_solution/public/overview/pages/data_quality.tsx index 37fc92709499..e785e5843543 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/data_quality.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/data_quality.tsx @@ -28,9 +28,10 @@ import { KibanaServices, useKibana, useToasts, useUiSetting$ } from '../../commo import { SpyRoute } from '../../common/utils/route/spy_routes'; import { useSignalIndex } from '../../detections/containers/detection_engine/alerts/use_signal_index'; import * as i18n from './translations'; -import type { - ReportDataQualityCheckAllCompletedParams, - ReportDataQualityIndexCheckedParams, +import { + type ReportDataQualityCheckAllCompletedParams, + type ReportDataQualityIndexCheckedParams, + DataQualityEventTypes, } from '../../common/lib/telemetry'; const LOCAL_STORAGE_KEY = 'dataQualityDashboardLastChecked'; @@ -118,14 +119,14 @@ const DataQualityComponent: React.FC = () => { const reportDataQualityIndexChecked = useCallback( (params: ReportDataQualityIndexCheckedParams) => { - telemetry.reportDataQualityIndexChecked(params); + telemetry.reportEvent(DataQualityEventTypes.DataQualityIndexChecked, params); }, [telemetry] ); const reportDataQualityCheckAllCompleted = useCallback( (params: ReportDataQualityCheckAllCompletedParams) => { - telemetry.reportDataQualityCheckAllCompleted(params); + telemetry.reportEvent(DataQualityEventTypes.DataQualityCheckAllCompleted, params); }, [telemetry] ); @@ -171,6 +172,8 @@ const DataQualityComponent: React.FC = () => { startDate={startDate} theme={theme} toasts={toasts} + defaultStartTime={DEFAULT_START_TIME} + defaultEndTime={DEFAULT_END_TIME} /> ) : ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx index 75c074c51775..4e298e50d2a2 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/graph_overlay/index.tsx @@ -29,12 +29,12 @@ import { useGlobalFullScreen, useTimelineFullScreen, } from '../../../common/containers/use_full_screen'; -import { isFullScreen } from '../timeline/body/column_headers'; import { inputsActions } from '../../../common/store/actions'; import { Resolver } from '../../../resolver/view'; import { useTimelineDataFilters } from '../../containers/use_timeline_data_filters'; import { timelineSelectors } from '../../store'; import { timelineDefaults } from '../../store/defaults'; +import { isFullScreen } from '../timeline/helpers'; const SESSION_VIEW_FULL_SCREEN = 'sessionViewFullScreen'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/modal/actions/new_timeline_button.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/modal/actions/new_timeline_button.test.tsx index c26b34dffcaf..92f9b874f874 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/modal/actions/new_timeline_button.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/modal/actions/new_timeline_button.test.tsx @@ -12,7 +12,7 @@ import { TimelineId } from '../../../../../common/types'; import { timelineActions } from '../../../store'; import { TestProviders } from '../../../../common/mock'; import { RowRendererValues } from '../../../../../common/api/timeline'; -import { defaultUdtHeaders } from '../../timeline/unified_components/default_headers'; +import { defaultUdtHeaders } from '../../timeline/body/column_headers/default_headers'; jest.mock('../../../../common/components/discover_in_timeline/use_discover_in_timeline_context'); jest.mock('../../../../common/hooks/use_selector'); diff --git a/x-pack/plugins/security_solution/public/timelines/components/new_timeline/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/new_timeline/index.test.tsx index 8e08e4b957d6..0d1ed98f0bc9 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/new_timeline/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/new_timeline/index.test.tsx @@ -17,7 +17,7 @@ import { TimelineTypeEnum, } from '../../../../common/api/timeline'; import { TestProviders } from '../../../common/mock'; -import { defaultUdtHeaders } from '../timeline/unified_components/default_headers'; +import { defaultUdtHeaders } from '../timeline/body/column_headers/default_headers'; jest.mock('../../../common/components/discover_in_timeline/use_discover_in_timeline_context'); jest.mock('../../../common/hooks/use_selector'); diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts index 5da977c30a41..917f1d1bc29d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.test.ts @@ -35,7 +35,7 @@ import { mockTemplate as mockSelectedTemplate, } from './__mocks__'; import { resolveTimeline } from '../../containers/api'; -import { defaultUdtHeaders } from '../timeline/unified_components/default_headers'; +import { defaultUdtHeaders } from '../timeline/body/column_headers/default_headers'; jest.mock('../../../common/hooks/use_experimental_features'); diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts index b3f84a82d4ed..e9c1d85b9049 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/helpers.ts @@ -35,7 +35,10 @@ import { useUpdateTimeline } from './use_update_timeline'; import type { TimelineModel } from '../../store/model'; import { timelineDefaults } from '../../store/defaults'; -import { defaultColumnHeaderType } from '../timeline/body/column_headers/default_headers'; +import { + defaultColumnHeaderType, + defaultUdtHeaders, +} from '../timeline/body/column_headers/default_headers'; import type { OpenTimelineResult, TimelineErrorCallback } from './types'; import { IS_OPERATOR } from '../timeline/data_providers/data_provider'; @@ -46,7 +49,6 @@ import { DEFAULT_TO_MOMENT, } from '../../../common/utils/default_date_settings'; import { resolveTimeline } from '../../containers/api'; -import { defaultUdtHeaders } from '../timeline/unified_components/default_headers'; import { timelineActions } from '../../store'; export const OPEN_TIMELINE_CLASS_NAME = 'open-timeline'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.tsx index 6afd900185af..8af06fe910f9 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.tsx @@ -53,7 +53,7 @@ import { SourcererScopeName } from '../../../sourcerer/store/model'; import { useSourcererDataView } from '../../../sourcerer/containers'; import { useStartTransaction } from '../../../common/lib/apm/use_start_transaction'; import { TIMELINE_ACTIONS } from '../../../common/lib/apm/user_actions'; -import { defaultUdtHeaders } from '../timeline/unified_components/default_headers'; +import { defaultUdtHeaders } from '../timeline/body/column_headers/default_headers'; import { timelineDefaults } from '../../store/defaults'; interface OwnProps { diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx index fe53c36d3f04..19f98aff651f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx @@ -34,6 +34,7 @@ import { SourcererScopeName } from '../../../../sourcerer/store/model'; import { useSourcererDataView } from '../../../../sourcerer/containers'; import { useDeleteNote } from './hooks/use_delete_note'; import { getTimelineNoteSelector } from '../../timeline/tabs/notes/selectors'; +import { DocumentEventTypes } from '../../../../common/lib/telemetry'; export const NotePreviewsContainer = styled.section` padding-top: ${({ theme }) => `${theme.eui.euiSizeS}`}; @@ -66,7 +67,7 @@ const ToggleEventDetailsButtonComponent: React.FC }, }, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: timelineId, panel: 'right', }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/__snapshots__/index.test.tsx.snap deleted file mode 100644 index 48209711babb..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,513 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = ` - -`; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/actions/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/actions/index.tsx deleted file mode 100644 index 025d12bc6ddc..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/actions/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 { EuiButtonIcon } from '@elastic/eui'; -import React, { useCallback } from 'react'; - -import type { ColumnHeaderOptions } from '../../../../../../../common/types'; -import type { OnColumnRemoved } from '../../../events'; -import { EventsHeadingExtra, EventsLoading } from '../../../styles'; -import type { Sort } from '../../sort'; - -import * as i18n from '../translations'; - -interface Props { - header: ColumnHeaderOptions; - isLoading: boolean; - onColumnRemoved: OnColumnRemoved; - sort: Sort[]; -} - -/** Given a `header`, returns the `SortDirection` applicable to it */ - -export const CloseButton = React.memo<{ - columnId: string; - onColumnRemoved: OnColumnRemoved; -}>(({ columnId, onColumnRemoved }) => { - const handleClick = useCallback( - (event: React.MouseEvent) => { - // To avoid a re-sorting when you delete a column - event.preventDefault(); - event.stopPropagation(); - onColumnRemoved(columnId); - }, - [columnId, onColumnRemoved] - ); - - return ( - - ); -}); - -CloseButton.displayName = 'CloseButton'; - -export const Actions = React.memo(({ header, onColumnRemoved, sort, isLoading }) => { - return ( - <> - {sort.some((i) => i.columnId === header.id) && isLoading ? ( - - - - ) : ( - - - - )} - - ); -}); - -Actions.displayName = 'Actions'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx deleted file mode 100644 index 2048cefb9bf0..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx +++ /dev/null @@ -1,307 +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 { EuiContextMenuPanelDescriptor } from '@elastic/eui'; -import { EuiContextMenu, EuiIcon, EuiPopover } from '@elastic/eui'; -import React, { useCallback, useMemo, useRef, useState } from 'react'; -import type { DraggableChildrenFn } from '@hello-pangea/dnd'; -import { Draggable } from '@hello-pangea/dnd'; -import type { ResizeCallback } from 're-resizable'; -import { Resizable } from 're-resizable'; -import { useDispatch } from 'react-redux'; -import styled from 'styled-components'; -import { DRAGGABLE_KEYBOARD_WRAPPER_CLASS_NAME } from '@kbn/securitysolution-t-grid'; - -import { useDraggableKeyboardWrapper } from '../../../../../common/components/drag_and_drop/draggable_keyboard_wrapper_hook'; -import { DEFAULT_COLUMN_MIN_WIDTH } from '../constants'; -import { getDraggableFieldId } from '../../../../../common/components/drag_and_drop/helpers'; -import type { ColumnHeaderOptions } from '../../../../../../common/types/timeline'; -import { TimelineTabs } from '../../../../../../common/types/timeline'; -import { Direction } from '../../../../../../common/search_strategy'; -import type { OnFilterChange } from '../../events'; -import { ARIA_COLUMN_INDEX_OFFSET } from '../../helpers'; -import { EventsTh, EventsThContent, EventsHeadingHandle } from '../../styles'; -import type { Sort } from '../sort'; - -import { Header } from './header'; -import { timelineActions } from '../../../../store'; - -import * as i18n from './translations'; - -const ContextMenu = styled(EuiContextMenu)` - width: 115px; - - & .euiContextMenuItem { - font-size: 12px; - padding: 4px 8px; - width: 115px; - } -`; - -const PopoverContainer = styled.div<{ $width: number }>` - & .euiPopover { - padding-right: 8px; - width: ${({ $width }) => $width}px; - } -`; - -const RESIZABLE_ENABLE = { right: true }; - -interface ColumneHeaderProps { - draggableIndex: number; - header: ColumnHeaderOptions; - isDragging: boolean; - onFilterChange?: OnFilterChange; - sort: Sort[]; - tabType: TimelineTabs; - timelineId: string; -} - -const ColumnHeaderComponent: React.FC = ({ - draggableIndex, - header, - timelineId, - isDragging, - onFilterChange, - sort, - tabType, -}) => { - const keyboardHandlerRef = useRef(null); - const [hoverActionsOwnFocus, setHoverActionsOwnFocus] = useState(false); - const restoreFocus = useCallback(() => keyboardHandlerRef.current?.focus(), []); - - const dispatch = useDispatch(); - const resizableSize = useMemo( - () => ({ - width: header.initialWidth ?? DEFAULT_COLUMN_MIN_WIDTH, - height: 'auto', - }), - [header.initialWidth] - ); - const resizableStyle: { - position: 'absolute' | 'relative'; - } = useMemo( - () => ({ - position: isDragging ? 'absolute' : 'relative', - }), - [isDragging] - ); - const resizableHandleComponent = useMemo( - () => ({ - right: , - }), - [] - ); - const handleResizeStop: ResizeCallback = useCallback( - (e, direction, ref, delta) => { - dispatch( - timelineActions.applyDeltaToColumnWidth({ - columnId: header.id, - delta: delta.width, - id: timelineId, - }) - ); - }, - [dispatch, header.id, timelineId] - ); - const draggableId = useMemo( - () => - getDraggableFieldId({ - contextId: `timeline-column-headers-${tabType}-${timelineId}`, - fieldId: header.id, - }), - [tabType, timelineId, header.id] - ); - - const onColumnSort = useCallback( - (sortDirection: Direction) => { - const columnId = header.id; - const columnType = header.type ?? ''; - const esTypes = header.esTypes ?? []; - const headerIndex = sort.findIndex((col) => col.columnId === columnId); - const newSort = - headerIndex === -1 - ? [ - ...sort, - { - columnId, - columnType, - esTypes, - sortDirection, - }, - ] - : [ - ...sort.slice(0, headerIndex), - { - columnId, - columnType, - esTypes, - sortDirection, - }, - ...sort.slice(headerIndex + 1), - ]; - - dispatch( - timelineActions.updateSort({ - id: timelineId, - sort: newSort, - }) - ); - }, - [dispatch, header, sort, timelineId] - ); - - const handleClosePopOverTrigger = useCallback(() => { - setHoverActionsOwnFocus(false); - restoreFocus(); - }, [restoreFocus]); - - const panels: EuiContextMenuPanelDescriptor[] = useMemo( - () => [ - { - id: 0, - items: [ - { - icon: , - name: i18n.HIDE_COLUMN, - onClick: () => { - dispatch(timelineActions.removeColumn({ id: timelineId, columnId: header.id })); - handleClosePopOverTrigger(); - }, - }, - ...(tabType !== TimelineTabs.eql - ? [ - { - disabled: !header.aggregatable, - icon: , - name: i18n.SORT_AZ, - onClick: () => { - onColumnSort(Direction.asc); - handleClosePopOverTrigger(); - }, - }, - { - disabled: !header.aggregatable, - icon: , - name: i18n.SORT_ZA, - onClick: () => { - onColumnSort(Direction.desc); - handleClosePopOverTrigger(); - }, - }, - ] - : []), - ], - }, - ], - [ - dispatch, - handleClosePopOverTrigger, - header.aggregatable, - header.id, - onColumnSort, - tabType, - timelineId, - ] - ); - - const headerButton = useMemo( - () => ( -
    - ), - [header, onFilterChange, sort, timelineId] - ); - - const DraggableContent = useCallback( - (dragProvided) => ( - - - - - - - - - - ), - [handleClosePopOverTrigger, headerButton, header.initialWidth, hoverActionsOwnFocus, panels] - ); - - const onFocus = useCallback(() => { - keyboardHandlerRef.current?.focus(); - }, []); - - const openPopover = useCallback(() => { - setHoverActionsOwnFocus(true); - }, []); - - const { onBlur, onKeyDown } = useDraggableKeyboardWrapper({ - closePopover: handleClosePopOverTrigger, - draggableId, - fieldName: header.id, - keyboardHandlerRef, - openPopover, - }); - - const keyDownHandler = useCallback( - (keyboardEvent: React.KeyboardEvent) => { - if (!hoverActionsOwnFocus) { - onKeyDown(keyboardEvent); - } - }, - [hoverActionsOwnFocus, onKeyDown] - ); - - return ( - -
    - - {DraggableContent} - -
    -
    - ); -}; - -export const ColumnHeader = React.memo(ColumnHeaderComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/default_headers.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/default_headers.ts index 56c29462415b..a249f2ef2a85 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/default_headers.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/default_headers.ts @@ -6,51 +6,48 @@ */ import type { ColumnHeaderOptions, ColumnHeaderType } from '../../../../../../common/types'; -import { DEFAULT_COLUMN_MIN_WIDTH, DEFAULT_DATE_COLUMN_MIN_WIDTH } from '../constants'; +import { + DEFAULT_COLUMN_MIN_WIDTH, + DEFAULT_UNIFIED_TABLE_DATE_COLUMN_MIN_WIDTH, +} from '../constants'; export const defaultColumnHeaderType: ColumnHeaderType = 'not-filtered'; -export const defaultHeaders: ColumnHeaderOptions[] = [ +export const defaultUdtHeaders: ColumnHeaderOptions[] = [ { columnHeaderType: defaultColumnHeaderType, id: '@timestamp', - initialWidth: DEFAULT_DATE_COLUMN_MIN_WIDTH, + initialWidth: DEFAULT_UNIFIED_TABLE_DATE_COLUMN_MIN_WIDTH, esTypes: ['date'], type: 'date', }, { columnHeaderType: defaultColumnHeaderType, id: 'message', - initialWidth: DEFAULT_COLUMN_MIN_WIDTH, + initialWidth: DEFAULT_COLUMN_MIN_WIDTH * 2, }, { columnHeaderType: defaultColumnHeaderType, id: 'event.category', - initialWidth: DEFAULT_COLUMN_MIN_WIDTH, }, { columnHeaderType: defaultColumnHeaderType, id: 'event.action', - initialWidth: DEFAULT_COLUMN_MIN_WIDTH, }, { columnHeaderType: defaultColumnHeaderType, id: 'host.name', - initialWidth: DEFAULT_COLUMN_MIN_WIDTH, }, { columnHeaderType: defaultColumnHeaderType, id: 'source.ip', - initialWidth: DEFAULT_COLUMN_MIN_WIDTH, }, { columnHeaderType: defaultColumnHeaderType, id: 'destination.ip', - initialWidth: DEFAULT_COLUMN_MIN_WIDTH, }, { columnHeaderType: defaultColumnHeaderType, id: 'user.name', - initialWidth: DEFAULT_COLUMN_MIN_WIDTH, }, ]; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/filter/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/filter/__snapshots__/index.test.tsx.snap deleted file mode 100644 index ed15a5f635e9..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/filter/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,9 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Filter renders correctly against snapshot 1`] = ` - -`; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/filter/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/filter/index.test.tsx deleted file mode 100644 index bd6e75efd94d..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/filter/index.test.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { mount, shallow } from 'enzyme'; -import React from 'react'; - -import { defaultHeaders } from '../default_headers'; - -import { Filter } from '.'; -import type { ColumnHeaderType } from '../../../../../../../common/types'; - -const textFilter: ColumnHeaderType = 'text-filter'; -const notFiltered: ColumnHeaderType = 'not-filtered'; - -describe('Filter', () => { - test('renders correctly against snapshot', () => { - const textFilterColumnHeader = { - ...defaultHeaders[0], - columnHeaderType: textFilter, - }; - - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); - - describe('rendering', () => { - test('it renders a text filter when the columnHeaderType is "text-filter"', () => { - const textFilterColumnHeader = { - ...defaultHeaders[0], - columnHeaderType: textFilter, - }; - - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="textFilter"]').first().props()).toHaveProperty( - 'placeholder' - ); - }); - - test('it does NOT render a filter when the columnHeaderType is "not-filtered"', () => { - const notFilteredHeader = { - ...defaultHeaders[0], - columnHeaderType: notFiltered, - }; - - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="textFilter"]').exists()).toEqual(false); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/filter/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/filter/index.tsx deleted file mode 100644 index 3eb2cda8af24..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/filter/index.tsx +++ /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. - */ - -import { noop } from 'lodash/fp'; -import React from 'react'; - -import type { ColumnHeaderOptions } from '../../../../../../../common/types'; -import { DEFAULT_COLUMN_MIN_WIDTH } from '../../constants'; -import type { OnFilterChange } from '../../../events'; -import { TextFilter } from '../text_filter'; - -interface Props { - header: ColumnHeaderOptions; - onFilterChange?: OnFilterChange; -} - -/** Renders a header's filter, based on the `columnHeaderType` */ -export const Filter = React.memo(({ header, onFilterChange = noop }) => { - switch (header.columnHeaderType) { - case 'text-filter': - return ( - - ); - case 'not-filtered': // fall through - default: - return null; - } -}); - -Filter.displayName = 'Filter'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/__snapshots__/index.test.tsx.snap deleted file mode 100644 index 0a621f021833..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,77 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Header renders correctly against snapshot 1`] = ` - - - - - - -`; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/header_content.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/header_content.tsx deleted file mode 100644 index 24b75c88d796..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/header_content.tsx +++ /dev/null @@ -1,84 +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 { EuiToolTip } from '@elastic/eui'; -import { noop } from 'lodash/fp'; -import React from 'react'; -import type { ColumnHeaderOptions } from '../../../../../../../common/types/timeline'; - -import { TruncatableText } from '../../../../../../common/components/truncatable_text'; -import { EventsHeading, EventsHeadingTitleButton, EventsHeadingTitleSpan } from '../../../styles'; -import type { Sort } from '../../sort'; -import { SortIndicator } from '../../sort/sort_indicator'; -import { HeaderToolTipContent } from '../header_tooltip_content'; -import { getSortDirection, getSortIndex } from './helpers'; -interface HeaderContentProps { - children: React.ReactNode; - header: ColumnHeaderOptions; - isLoading: boolean; - isResizing: boolean; - onClick: () => void; - showSortingCapability: boolean; - sort: Sort[]; -} - -const HeaderContentComponent: React.FC = ({ - children, - header, - isLoading, - isResizing, - onClick, - showSortingCapability, - sort, -}) => ( - - {header.aggregatable && showSortingCapability ? ( - - - } - > - <> - {React.isValidElement(header.display) - ? header.display - : header.displayAsText ?? header.id} - - - - - - - ) : ( - - - } - > - <> - {React.isValidElement(header.display) - ? header.display - : header.displayAsText ?? header.id} - - - - - )} - - {children} - -); - -export const HeaderContent = React.memo(HeaderContentComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/helpers.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/helpers.ts deleted file mode 100644 index e31ed05e5592..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/helpers.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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { Direction } from '../../../../../../../common/search_strategy'; -import type { - ColumnHeaderOptions, - SortDirection, -} from '../../../../../../../common/types/timeline'; -import type { Sort } from '../../sort'; - -interface GetNewSortDirectionOnClickParams { - clickedHeader: ColumnHeaderOptions; - currentSort: Sort[]; -} - -/** Given a `header`, returns the `SortDirection` applicable to it */ -export const getNewSortDirectionOnClick = ({ - clickedHeader, - currentSort, -}: GetNewSortDirectionOnClickParams): Direction => - currentSort.reduce( - (acc, item) => (clickedHeader.id === item.columnId ? getNextSortDirection(item) : acc), - Direction.desc - ); - -/** Given a current sort direction, it returns the next sort direction */ -export const getNextSortDirection = (currentSort: Sort): Direction => { - switch (currentSort.sortDirection) { - case Direction.desc: - return Direction.asc; - case Direction.asc: - return Direction.desc; - case 'none': - return Direction.desc; - default: - return Direction.desc; - } -}; - -interface GetSortDirectionParams { - header: ColumnHeaderOptions; - sort: Sort[]; -} - -export const getSortDirection = ({ header, sort }: GetSortDirectionParams): SortDirection => - sort.reduce( - (acc, item) => (header.id === item.columnId ? item.sortDirection : acc), - 'none' - ); - -export const getSortIndex = ({ header, sort }: GetSortDirectionParams): number => - sort.findIndex((s) => s.columnId === header.id); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx deleted file mode 100644 index abf452b834a1..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.test.tsx +++ /dev/null @@ -1,364 +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 { mount, shallow } from 'enzyme'; -import React, { type ReactNode } from 'react'; - -import { timelineActions } from '../../../../../store'; -import { TestProviders } from '../../../../../../common/mock'; -import type { Sort } from '../../sort'; -import { CloseButton } from '../actions'; -import { defaultHeaders } from '../default_headers'; - -import { HeaderComponent } from '.'; -import { getNewSortDirectionOnClick, getNextSortDirection, getSortDirection } from './helpers'; -import { Direction } from '../../../../../../../common/search_strategy'; -import { useDeepEqualSelector } from '../../../../../../common/hooks/use_selector'; -import type { ColumnHeaderType } from '../../../../../../../common/types'; -import { TimelineId } from '../../../../../../../common/types/timeline'; - -const mockDispatch = jest.fn(); -jest.mock('react-redux', () => { - const original = jest.requireActual('react-redux'); - - return { - ...original, - useSelector: jest.fn(), - useDispatch: () => mockDispatch, - }; -}); - -jest.mock('../../../../../../common/hooks/use_selector', () => ({ - useShallowEqualSelector: jest.fn(), - useDeepEqualSelector: jest.fn(), -})); - -const filteredColumnHeader: ColumnHeaderType = 'text-filter'; - -describe('Header', () => { - const columnHeader = defaultHeaders[0]; - const sort: Sort[] = [ - { - columnId: columnHeader.id, - columnType: columnHeader.type ?? '', - esTypes: columnHeader.esTypes ?? [], - sortDirection: Direction.desc, - }, - ]; - const timelineId = TimelineId.test; - - beforeEach(() => { - (useDeepEqualSelector as jest.Mock).mockReturnValue({ isLoading: false }); - }); - - test('renders correctly against snapshot', () => { - const wrapper = shallow( - - - - ); - expect(wrapper.find('HeaderComponent').dive()).toMatchSnapshot(); - }); - - describe('rendering', () => { - test('it renders the header text', () => { - const wrapper = mount( - - - - ); - - expect( - wrapper.find(`[data-test-subj="header-text-${columnHeader.id}"]`).first().text() - ).toEqual(columnHeader.id); - }); - - test('it renders the header text alias when displayAsText is provided', () => { - const displayAsText = 'Timestamp'; - const headerWithLabel = { ...columnHeader, displayAsText }; - const wrapper = mount( - - - - ); - - expect( - wrapper.find(`[data-test-subj="header-text-${columnHeader.id}"]`).first().text() - ).toEqual(displayAsText); - }); - - test('it renders the header as a `ReactNode` when `display` is provided', () => { - const display: React.ReactNode = ( -
    - {'The display property renders the column heading as a ReactNode'} -
    - ); - const headerWithLabel = { ...columnHeader, display }; - const wrapper = mount( - - - - ); - - expect(wrapper.find(`[data-test-subj="rendered-via-display"]`).exists()).toBe(true); - }); - - test('it prefers to render `display` instead of `displayAsText` when both are provided', () => { - const displayAsText = 'this text should NOT be rendered'; - const display: React.ReactNode = ( -
    {'this text is rendered via display'}
    - ); - const headerWithLabel = { ...columnHeader, display, displayAsText }; - const wrapper = mount( - - - - ); - - expect(wrapper.text()).toBe('this text is rendered via display'); - }); - - test('it falls back to rendering header.id when `display` is not a valid React node', () => { - const display = {} as unknown as ReactNode; // a plain object is NOT a `ReactNode` - const headerWithLabel = { ...columnHeader, display }; - const wrapper = mount( - - - - ); - - expect( - wrapper.find(`[data-test-subj="header-text-${columnHeader.id}"]`).first().text() - ).toEqual(columnHeader.id); - }); - - test('it renders a sort indicator', () => { - const headerSortable = { ...columnHeader, aggregatable: true }; - const wrapper = mount( - - - - ); - - expect(wrapper.find('[data-test-subj="header-sort-indicator"]').first().exists()).toEqual( - true - ); - }); - - test('it renders a filter', () => { - const columnWithFilter = { - ...columnHeader, - columnHeaderType: filteredColumnHeader, - }; - - const wrapper = mount( - - - - ); - - expect(wrapper.find('[data-test-subj="textFilter"]').first().props()).toHaveProperty( - 'placeholder' - ); - }); - }); - - describe('onColumnSorted', () => { - test('it invokes the onColumnSorted callback when the header sort button is clicked', () => { - const headerSortable = { ...columnHeader, aggregatable: true }; - const wrapper = mount( - - - - ); - - wrapper.find('[data-test-subj="header-sort-button"]').first().simulate('click'); - - expect(mockDispatch).toBeCalledWith( - timelineActions.updateSort({ - id: timelineId, - sort: [ - { - columnId: columnHeader.id, - columnType: columnHeader.type ?? 'number', - esTypes: columnHeader.esTypes ?? [], - sortDirection: Direction.asc, // (because the previous state was Direction.desc) - }, - ], - }) - ); - }); - - test('it does NOT render the header sort button when aggregatable is false', () => { - const headerSortable = { ...columnHeader, aggregatable: false }; - const wrapper = mount( - - - - ); - - expect(wrapper.find('[data-test-subj="header-sort-button"]').length).toEqual(0); - }); - - test('it does NOT render the header sort button when aggregatable is missing', () => { - const headerSortable = { ...columnHeader }; - const wrapper = mount( - - - - ); - - expect(wrapper.find('[data-test-subj="header-sort-button"]').length).toEqual(0); - }); - - test('it does NOT invoke the onColumnSorted callback when the header is clicked and aggregatable is undefined', () => { - const mockOnColumnSorted = jest.fn(); - const headerSortable = { ...columnHeader, aggregatable: undefined }; - const wrapper = mount( - - - - ); - - wrapper.find(`[data-test-subj="header-${columnHeader.id}"]`).first().simulate('click'); - - expect(mockOnColumnSorted).not.toHaveBeenCalled(); - }); - }); - - describe('CloseButton', () => { - test('it invokes the onColumnRemoved callback with the column ID when the close button is clicked', () => { - const mockOnColumnRemoved = jest.fn(); - - const wrapper = mount( - - ); - - wrapper.find('[data-test-subj="remove-column"]').first().simulate('click'); - - expect(mockOnColumnRemoved).toBeCalledWith(columnHeader.id); - }); - }); - - describe('getSortDirection', () => { - test('it returns the sort direction when the header id matches the sort column id', () => { - expect(getSortDirection({ header: columnHeader, sort })).toEqual(sort[0].sortDirection); - }); - - test('it returns "none" when sort direction when the header id does NOT match the sort column id', () => { - const nonMatching: Sort[] = [ - { - columnId: 'differentSocks', - columnType: columnHeader.type ?? 'number', - esTypes: columnHeader.esTypes ?? [], - sortDirection: Direction.desc, - }, - ]; - - expect(getSortDirection({ header: columnHeader, sort: nonMatching })).toEqual('none'); - }); - }); - - describe('getNextSortDirection', () => { - test('it returns "asc" when the current direction is "desc"', () => { - const sortDescending: Sort = { - columnId: columnHeader.id, - columnType: columnHeader.type ?? 'number', - esTypes: columnHeader.esTypes ?? [], - sortDirection: Direction.desc, - }; - - expect(getNextSortDirection(sortDescending)).toEqual('asc'); - }); - - test('it returns "desc" when the current direction is "asc"', () => { - const sortAscending: Sort = { - columnId: columnHeader.id, - columnType: columnHeader.type ?? 'number', - esTypes: columnHeader.esTypes ?? [], - sortDirection: Direction.asc, - }; - - expect(getNextSortDirection(sortAscending)).toEqual(Direction.desc); - }); - - test('it returns "desc" by default', () => { - const sortNone: Sort = { - columnId: columnHeader.id, - columnType: columnHeader.type ?? 'number', - esTypes: columnHeader.esTypes ?? [], - sortDirection: 'none', - }; - - expect(getNextSortDirection(sortNone)).toEqual(Direction.desc); - }); - }); - - describe('getNewSortDirectionOnClick', () => { - test('it returns the expected new sort direction when the header id matches the sort column id', () => { - const sortMatches: Sort[] = [ - { - columnId: columnHeader.id, - columnType: columnHeader.type ?? 'number', - esTypes: columnHeader.esTypes ?? [], - sortDirection: Direction.desc, - }, - ]; - - expect( - getNewSortDirectionOnClick({ - clickedHeader: columnHeader, - currentSort: sortMatches, - }) - ).toEqual(Direction.asc); - }); - - test('it returns the expected new sort direction when the header id does NOT match the sort column id', () => { - const sortDoesNotMatch: Sort[] = [ - { - columnId: 'someOtherColumn', - columnType: columnHeader.type ?? 'number', - esTypes: columnHeader.esTypes ?? [], - sortDirection: 'none', - }, - ]; - - expect( - getNewSortDirectionOnClick({ - clickedHeader: columnHeader, - currentSort: sortDoesNotMatch, - }) - ).toEqual(Direction.desc); - }); - }); - - describe('text truncation styling', () => { - test('truncates the header text with an ellipsis', () => { - const wrapper = mount( - - - - ); - - expect( - wrapper.find(`[data-test-subj="header-text-${columnHeader.id}"]`).at(1) - ).toHaveStyleRule('text-overflow', 'ellipsis'); - }); - }); - - describe('header tooltip', () => { - test('it has a tooltip to display the properties of the field', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.find('[data-test-subj="header-tooltip"]').exists()).toEqual(true); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx deleted file mode 100644 index 08af0bf9cbdd..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/index.tsx +++ /dev/null @@ -1,118 +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 { noop } from 'lodash/fp'; -import React, { useCallback, useMemo } from 'react'; -import { useDispatch } from 'react-redux'; -import { isDataViewFieldSubtypeNested } from '@kbn/es-query'; - -import type { ColumnHeaderOptions } from '../../../../../../../common/types'; -import { - useDeepEqualSelector, - useShallowEqualSelector, -} from '../../../../../../common/hooks/use_selector'; -import { timelineActions, timelineSelectors } from '../../../../../store'; -import type { OnColumnRemoved, OnFilterChange } from '../../../events'; -import type { Sort } from '../../sort'; -import { Actions } from '../actions'; -import { Filter } from '../filter'; -import { getNewSortDirectionOnClick } from './helpers'; -import { HeaderContent } from './header_content'; -import { isEqlOnSelector } from './selectors'; - -interface Props { - header: ColumnHeaderOptions; - onFilterChange?: OnFilterChange; - sort: Sort[]; - timelineId: string; -} - -export const HeaderComponent: React.FC = ({ - header, - onFilterChange = noop, - sort, - timelineId, -}) => { - const dispatch = useDispatch(); - const getIsEqlOn = useMemo(() => isEqlOnSelector(), []); - const isEqlOn = useShallowEqualSelector((state) => getIsEqlOn(state, timelineId)); - - const onColumnSort = useCallback(() => { - const columnId = header.id; - const columnType = header.type ?? ''; - const esTypes = header.esTypes ?? []; - const sortDirection = getNewSortDirectionOnClick({ - clickedHeader: header, - currentSort: sort, - }); - const headerIndex = sort.findIndex((col) => col.columnId === columnId); - let newSort = []; - if (headerIndex === -1) { - newSort = [ - ...sort, - { - columnId, - columnType, - esTypes, - sortDirection, - }, - ]; - } else { - newSort = [ - ...sort.slice(0, headerIndex), - { - columnId, - columnType, - esTypes, - sortDirection, - }, - ...sort.slice(headerIndex + 1), - ]; - } - dispatch( - timelineActions.updateSort({ - id: timelineId, - sort: newSort, - }) - ); - }, [dispatch, header, sort, timelineId]); - - const onColumnRemoved = useCallback( - (columnId) => dispatch(timelineActions.removeColumn({ id: timelineId, columnId })), - [dispatch, timelineId] - ); - - const getManageTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); - const { isLoading } = useDeepEqualSelector( - (state) => getManageTimeline(state, timelineId) || { isLoading: false } - ); - const showSortingCapability = !isEqlOn && !isDataViewFieldSubtypeNested(header); - - return ( - <> - - - - - - - ); -}; - -export const Header = React.memo(HeaderComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/selectors.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/selectors.tsx deleted file mode 100644 index cac232fd6ea3..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header/selectors.tsx +++ /dev/null @@ -1,13 +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 { createSelector } from 'reselect'; -import { TimelineTabs } from '../../../../../../../common/types/timeline'; -import { selectTimeline } from '../../../../../store/selectors'; - -export const isEqlOnSelector = () => - createSelector(selectTimeline, (timeline) => timeline?.activeTab === TimelineTabs.eql); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header_tooltip_content/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header_tooltip_content/__snapshots__/index.test.tsx.snap deleted file mode 100644 index 750f3956786a..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header_tooltip_content/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,67 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`HeaderToolTipContent it renders the expected table content 1`] = ` - -

    - - Category - : - - - base - -

    -

    - - Field - : - - - @timestamp - -

    -

    - - Type - : - - - - - date - - -

    -

    - - Description - : - - - Date/time when the event originated. -For log events this is the date/time when the event was generated, and not when it was read. -Required field for all events. - -

    -
    -`; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header_tooltip_content/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header_tooltip_content/index.test.tsx deleted file mode 100644 index d2a134f37aba..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header_tooltip_content/index.test.tsx +++ /dev/null @@ -1,89 +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 { mount, shallow } from 'enzyme'; -import { cloneDeep } from 'lodash/fp'; -import React from 'react'; - -import type { ColumnHeaderOptions } from '../../../../../../../common/types'; -import { defaultHeaders } from '../../../../../../common/mock'; -import { HeaderToolTipContent } from '.'; - -describe('HeaderToolTipContent', () => { - let header: ColumnHeaderOptions; - beforeEach(() => { - header = cloneDeep(defaultHeaders[0]); - }); - - test('it renders the category', () => { - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="category-value"]').first().text()).toEqual( - header.category - ); - }); - - test('it renders the name of the field', () => { - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="field-value"]').first().text()).toEqual(header.id); - }); - - test('it renders the expected icon for the header type', () => { - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="type-icon"]').first().props().type).toEqual('clock'); - }); - - test('it renders the type of the field', () => { - const wrapper = mount(); - - expect( - wrapper - .find(`[data-test-subj="type-value-${header.esTypes?.at(0)}"]`) - .first() - .text() - ).toEqual(header.esTypes?.at(0)); - }); - - test('it renders multiple `esTypes`', () => { - const hasMultipleTypes = { ...header, esTypes: ['long', 'date'] }; - - const wrapper = mount(); - - hasMultipleTypes.esTypes.forEach((esType) => { - expect(wrapper.find(`[data-test-subj="type-value-${esType}"]`).first().text()).toEqual( - esType - ); - }); - }); - - test('it renders the description of the field', () => { - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="description-value"]').first().text()).toEqual( - header.description - ); - }); - - test('it does NOT render the description column when the field does NOT contain a description', () => { - const noDescription = { - ...header, - description: '', - }; - - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="description"]').exists()).toEqual(false); - }); - - test('it renders the expected table content', () => { - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header_tooltip_content/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header_tooltip_content/index.tsx deleted file mode 100644 index c96f3473a006..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/header_tooltip_content/index.tsx +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiIcon, EuiBadge } from '@elastic/eui'; -import { isEmpty } from 'lodash/fp'; -import React from 'react'; -import styled from 'styled-components'; - -import type { ColumnHeaderOptions } from '../../../../../../../common/types'; -import { getIconFromType } from '../../../../../../common/components/event_details/helpers'; -import * as i18n from '../translations'; - -const IconType = styled(EuiIcon)` - margin-right: 3px; - position: relative; - top: -2px; -`; -IconType.displayName = 'IconType'; - -const P = styled.span` - margin-bottom: 5px; -`; -P.displayName = 'P'; - -const ToolTipTableMetadata = styled.span` - margin-right: 5px; - display: block; - font-weight: bold; -`; -ToolTipTableMetadata.displayName = 'ToolTipTableMetadata'; - -const ToolTipTableValue = styled.span` - word-wrap: break-word; -`; -ToolTipTableValue.displayName = 'ToolTipTableValue'; - -export const HeaderToolTipContent = React.memo<{ header: ColumnHeaderOptions }>(({ header }) => ( - <> - {!isEmpty(header.category) && ( -

    - - {i18n.CATEGORY} - {':'} - - {header.category} -

    - )} -

    - - {i18n.FIELD} - {':'} - - {header.id} -

    -

    - - {i18n.TYPE} - {':'} - - - - {header.esTypes?.map((esType) => ( - - {esType} - - ))} - -

    - {!isEmpty(header.description) && ( -

    - - {i18n.DESCRIPTION} - {':'} - - - {header.description} - -

    - )} - -)); -HeaderToolTipContent.displayName = 'HeaderToolTipContent'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/helpers.test.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/helpers.test.ts index 8a4f024daac8..816ba731ba4f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/helpers.test.ts @@ -9,8 +9,7 @@ import { mockBrowserFields } from '../../../../../common/containers/source/mock' import type { BrowserFields } from '../../../../../../common/search_strategy'; import type { ColumnHeaderOptions } from '../../../../../../common/types'; import { DEFAULT_COLUMN_MIN_WIDTH, DEFAULT_DATE_COLUMN_MIN_WIDTH } from '../constants'; -import { defaultHeaders } from './default_headers'; -import { defaultUdtHeaders } from '../../unified_components/default_headers'; +import { defaultUdtHeaders } from './default_headers'; import { getColumnWidthFromType, getColumnHeaders, @@ -88,7 +87,7 @@ describe('helpers', () => { }); }); - test('should return the expected metadata in case of unified header', () => { + test('should return the expected metadata in case of default header', () => { const inputHeaders = defaultUdtHeaders; expect(getColumnHeader('@timestamp', inputHeaders)).toEqual({ columnHeaderType: 'not-filtered', @@ -112,7 +111,7 @@ describe('helpers', () => { searchable: true, type: 'date', esTypes: ['date'], - initialWidth: 190, + initialWidth: 215, }, { aggregatable: true, @@ -122,7 +121,6 @@ describe('helpers', () => { searchable: true, type: 'ip', esTypes: ['ip'], - initialWidth: 180, }, { aggregatable: true, @@ -132,10 +130,9 @@ describe('helpers', () => { searchable: true, type: 'ip', esTypes: ['ip'], - initialWidth: 180, }, ]; - const mockHeader = defaultHeaders.filter((h) => + const mockHeader = defaultUdtHeaders.filter((h) => ['@timestamp', 'source.ip', 'destination.ip'].includes(h.id) ); expect(getColumnHeaders(mockHeader, mockBrowserFields)).toEqual(expectedData); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.test.tsx deleted file mode 100644 index c20fcc45ea30..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.test.tsx +++ /dev/null @@ -1,336 +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 { shallow } from 'enzyme'; -import React from 'react'; - -import { defaultHeaders } from './default_headers'; -import { mockBrowserFields } from '../../../../../common/containers/source/mock'; -import type { Sort } from '../sort'; -import { TestProviders } from '../../../../../common/mock/test_providers'; -import { useMountAppended } from '../../../../../common/utils/use_mount_appended'; - -import type { ColumnHeadersComponentProps } from '.'; -import { ColumnHeadersComponent } from '.'; -import { cloneDeep } from 'lodash/fp'; -import { timelineActions } from '../../../../store'; -import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline'; -import { Direction } from '../../../../../../common/search_strategy'; -import { getDefaultControlColumn } from '../control_columns'; -import { testTrailingControlColumns } from '../../../../../common/mock/mock_timeline_control_columns'; -import type { UseFieldBrowserOptionsProps } from '../../../fields_browser'; -import { mockTriggersActionsUi } from '../../../../../common/mock/mock_triggers_actions_ui_plugin'; -import { mockTimelines } from '../../../../../common/mock/mock_timelines_plugin'; -import { HeaderActions } from '../../../../../common/components/header_actions/header_actions'; -import { getActionsColumnWidth } from '../../../../../common/components/header_actions'; - -jest.mock('../../../../../common/lib/kibana', () => ({ - useKibana: () => ({ - services: { - timelines: mockTimelines, - triggersActionsUi: mockTriggersActionsUi, - }, - }), -})); - -const mockUseFieldBrowserOptions = jest.fn(); -jest.mock('../../../fields_browser', () => ({ - useFieldBrowserOptions: (props: UseFieldBrowserOptionsProps) => mockUseFieldBrowserOptions(props), -})); - -const mockDispatch = jest.fn(); -jest.mock('react-redux', () => { - const original = jest.requireActual('react-redux'); - - return { - ...original, - useDispatch: () => mockDispatch, - }; -}); -const timelineId = TimelineId.test; - -describe('ColumnHeaders', () => { - const mount = useMountAppended(); - const ACTION_BUTTON_COUNT = 4; - const actionsColumnWidth = getActionsColumnWidth(ACTION_BUTTON_COUNT); - const leadingControlColumns = getDefaultControlColumn(ACTION_BUTTON_COUNT).map((x) => ({ - ...x, - headerCellRender: HeaderActions, - })); - const sort: Sort[] = [ - { - columnId: '@timestamp', - columnType: 'date', - esTypes: ['date'], - sortDirection: Direction.desc, - }, - ]; - const defaultProps: ColumnHeadersComponentProps = { - actionsColumnWidth, - browserFields: mockBrowserFields, - columnHeaders: defaultHeaders, - isSelectAllChecked: false, - onSelectAll: jest.fn, - show: true, - showEventsSelect: false, - showSelectAllCheckbox: false, - sort, - tabType: TimelineTabs.query, - timelineId, - leadingControlColumns, - trailingControlColumns: [], - }; - - describe('rendering', () => { - test('renders correctly against snapshot', () => { - const wrapper = shallow( - - - - ); - expect(wrapper.find('ColumnHeadersComponent')).toMatchSnapshot(); - }); - - test('it renders the field browser', () => { - const mockCloseEditor = jest.fn(); - mockUseFieldBrowserOptions.mockImplementation(({ editorActionsRef }) => { - editorActionsRef.current = { closeEditor: mockCloseEditor }; - return {}; - }); - const wrapper = mount( - - - - ); - - expect(wrapper.find('[data-test-subj="field-browser"]').first().exists()).toEqual(true); - }); - - test('it renders every column header', () => { - const wrapper = mount( - - - - ); - - defaultHeaders.forEach((h) => { - expect(wrapper.find('[data-test-subj="headers-group"]').first().text()).toContain(h.id); - }); - }); - }); - - describe('#onColumnsSorted', () => { - let mockSort: Sort[] = [ - { - columnId: '@timestamp', - columnType: 'date', - esTypes: ['date'], - sortDirection: Direction.desc, - }, - { - columnId: 'host.name', - columnType: 'string', - esTypes: [], - sortDirection: Direction.asc, - }, - ]; - let mockDefaultHeaders = cloneDeep( - defaultHeaders.map((h) => (h.id === 'message' ? h : { ...h, aggregatable: true })) - ); - - beforeEach(() => { - mockDefaultHeaders = cloneDeep( - defaultHeaders.map((h) => (h.id === 'message' ? h : { ...h, aggregatable: true })) - ); - mockSort = [ - { - columnId: '@timestamp', - columnType: 'date', - esTypes: ['date'], - sortDirection: Direction.desc, - }, - { - columnId: 'host.name', - columnType: 'string', - esTypes: [], - sortDirection: Direction.asc, - }, - ]; - }); - - test('Add column `event.category` as desc sorting', () => { - const wrapper = mount( - - - - ); - - wrapper - .find('[data-test-subj="header-event.category"] [data-test-subj="header-sort-button"]') - .first() - .simulate('click'); - - expect(mockDispatch).toHaveBeenCalledWith( - timelineActions.updateSort({ - id: timelineId, - sort: [ - { - columnId: '@timestamp', - columnType: 'date', - esTypes: ['date'], - sortDirection: Direction.desc, - }, - { - columnId: 'host.name', - columnType: 'string', - esTypes: [], - sortDirection: Direction.asc, - }, - { - columnId: 'event.category', - columnType: '', - esTypes: [], - sortDirection: Direction.desc, - }, - ], - }) - ); - }); - - test('Change order of column `@timestamp` from desc to asc without changing index position', () => { - const wrapper = mount( - - - - ); - - wrapper - .find('[data-test-subj="header-@timestamp"] [data-test-subj="header-sort-button"]') - .first() - .simulate('click'); - expect(mockDispatch).toHaveBeenCalledWith( - timelineActions.updateSort({ - id: timelineId, - sort: [ - { - columnId: '@timestamp', - columnType: 'date', - esTypes: ['date'], - sortDirection: Direction.asc, - }, - { - columnId: 'host.name', - columnType: 'string', - esTypes: [], - sortDirection: Direction.asc, - }, - ], - }) - ); - }); - - test('Change order of column `host.name` from asc to desc without changing index position', () => { - const wrapper = mount( - - - - ); - - wrapper - .find('[data-test-subj="header-host.name"] [data-test-subj="header-sort-button"]') - .first() - .simulate('click'); - - expect(mockDispatch).toHaveBeenCalledWith( - timelineActions.updateSort({ - id: timelineId, - sort: [ - { - columnId: '@timestamp', - columnType: 'date', - esTypes: ['date'], - sortDirection: Direction.desc, - }, - { - columnId: 'host.name', - columnType: '', - esTypes: [], - sortDirection: Direction.desc, - }, - ], - }) - ); - }); - test('Does not render the default leading action column header and renders a custom trailing header', () => { - const wrapper = mount( - - - - ); - - expect(wrapper.exists('[data-test-subj="field-browser"]')).toBeFalsy(); - expect(wrapper.exists('[data-test-subj="test-header-action-cell"]')).toBeTruthy(); - }); - }); - - describe('Field Editor', () => { - test('Closes field editor when the timeline is unmounted', () => { - const mockCloseEditor = jest.fn(); - mockUseFieldBrowserOptions.mockImplementation(({ editorActionsRef }) => { - editorActionsRef.current = { closeEditor: mockCloseEditor }; - return {}; - }); - - const wrapper = mount( - - - - ); - expect(mockCloseEditor).not.toHaveBeenCalled(); - - wrapper.unmount(); - expect(mockCloseEditor).toHaveBeenCalled(); - }); - - test('Closes field editor when the timeline is closed', () => { - const mockCloseEditor = jest.fn(); - mockUseFieldBrowserOptions.mockImplementation(({ editorActionsRef }) => { - editorActionsRef.current = { closeEditor: mockCloseEditor }; - return {}; - }); - - const Proxy = (props: ColumnHeadersComponentProps) => ( - - - - ); - const wrapper = mount(); - expect(mockCloseEditor).not.toHaveBeenCalled(); - - wrapper.setProps({ ...defaultProps, show: false }); - expect(mockCloseEditor).toHaveBeenCalled(); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx deleted file mode 100644 index f343b9af8ed9..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx +++ /dev/null @@ -1,316 +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, { useState, useEffect, useCallback, useMemo, useRef } from 'react'; -import type { DraggableChildrenFn, DroppableProps } from '@hello-pangea/dnd'; -import { Droppable } from '@hello-pangea/dnd'; - -import { useDispatch } from 'react-redux'; -import type { ControlColumnProps, HeaderActionProps } from '../../../../../../common/types'; -import { removeColumn, upsertColumn } from '../../../../store/actions'; -import { DragEffects } from '../../../../../common/components/drag_and_drop/draggable_wrapper'; -import { DraggableFieldBadge } from '../../../../../common/components/draggables/field_badge'; -import type { BrowserFields } from '../../../../../common/containers/source'; -import { - DRAG_TYPE_FIELD, - droppableTimelineColumnsPrefix, -} from '../../../../../common/components/drag_and_drop/helpers'; -import type { ColumnHeaderOptions, TimelineTabs } from '../../../../../../common/types/timeline'; -import type { OnSelectAll } from '../../events'; -import { - EventsTh, - EventsThead, - EventsThGroupData, - EventsTrHeader, - EventsThGroupActions, -} from '../../styles'; -import type { Sort } from '../sort'; -import { ColumnHeader } from './column_header'; - -import { SourcererScopeName } from '../../../../../sourcerer/store/model'; -import type { FieldEditorActions } from '../../../fields_browser'; -import { useFieldBrowserOptions } from '../../../fields_browser'; - -export interface ColumnHeadersComponentProps { - actionsColumnWidth: number; - browserFields: BrowserFields; - columnHeaders: ColumnHeaderOptions[]; - isEventViewer?: boolean; - isSelectAllChecked: boolean; - onSelectAll: OnSelectAll; - show: boolean; - showEventsSelect: boolean; - showSelectAllCheckbox: boolean; - sort: Sort[]; - tabType: TimelineTabs; - timelineId: string; - leadingControlColumns: ControlColumnProps[]; - trailingControlColumns: ControlColumnProps[]; -} - -interface DraggableContainerProps { - children: React.ReactNode; - onMount: () => void; - onUnmount: () => void; -} - -export const DraggableContainer = React.memo( - ({ children, onMount, onUnmount }) => { - useEffect(() => { - onMount(); - - return () => onUnmount(); - }, [onMount, onUnmount]); - - return <>{children}; - } -); - -DraggableContainer.displayName = 'DraggableContainer'; - -export const isFullScreen = ({ - globalFullScreen, - isActiveTimelines, - timelineFullScreen, -}: { - globalFullScreen: boolean; - isActiveTimelines: boolean; - timelineFullScreen: boolean; -}) => - (isActiveTimelines && timelineFullScreen) || (isActiveTimelines === false && globalFullScreen); - -/** Renders the timeline header columns */ -export const ColumnHeadersComponent = ({ - actionsColumnWidth, - browserFields, - columnHeaders, - isEventViewer = false, - isSelectAllChecked, - onSelectAll, - show, - showEventsSelect, - showSelectAllCheckbox, - sort, - tabType, - timelineId, - leadingControlColumns, - trailingControlColumns, -}: ColumnHeadersComponentProps) => { - const dispatch = useDispatch(); - - const [draggingIndex, setDraggingIndex] = useState(null); - const fieldEditorActionsRef = useRef(null); - - useEffect(() => { - return () => { - if (fieldEditorActionsRef.current) { - // eslint-disable-next-line react-hooks/exhaustive-deps - fieldEditorActionsRef.current.closeEditor(); - } - }; - }, []); - - useEffect(() => { - if (!show && fieldEditorActionsRef.current) { - fieldEditorActionsRef.current.closeEditor(); - } - }, [show]); - - const renderClone: DraggableChildrenFn = useCallback( - (dragProvided, _dragSnapshot, rubric) => { - const index = rubric.source.index; - const header = columnHeaders[index]; - - const onMount = () => setDraggingIndex(index); - const onUnmount = () => setDraggingIndex(null); - - return ( - - - - - - - - ); - }, - [columnHeaders, setDraggingIndex] - ); - - const ColumnHeaderList = useMemo( - () => - columnHeaders.map((header, draggableIndex) => ( - - )), - [columnHeaders, timelineId, draggingIndex, sort, tabType] - ); - - const DroppableContent = useCallback( - (dropProvided, snapshot) => ( - <> - - {ColumnHeaderList} - - - ), - [ColumnHeaderList] - ); - - const leadingHeaderCells = useMemo( - () => - leadingControlColumns ? leadingControlColumns.map((column) => column.headerCellRender) : [], - [leadingControlColumns] - ); - - const trailingHeaderCells = useMemo( - () => - trailingControlColumns ? trailingControlColumns.map((column) => column.headerCellRender) : [], - [trailingControlColumns] - ); - - const fieldBrowserOptions = useFieldBrowserOptions({ - sourcererScope: SourcererScopeName.timeline, - editorActionsRef: fieldEditorActionsRef, - upsertColumn: (column, index) => dispatch(upsertColumn({ column, id: timelineId, index })), - removeColumn: (columnId) => dispatch(removeColumn({ columnId, id: timelineId })), - }); - - const LeadingHeaderActions = useMemo(() => { - return leadingHeaderCells.map( - (Header: React.ComponentType | React.ComponentType | undefined, index) => { - const passedWidth = leadingControlColumns[index] && leadingControlColumns[index].width; - const width = passedWidth ? passedWidth : actionsColumnWidth; - return ( - - {Header && ( -
    - )} - - ); - } - ); - }, [ - leadingHeaderCells, - leadingControlColumns, - actionsColumnWidth, - browserFields, - columnHeaders, - fieldBrowserOptions, - isEventViewer, - isSelectAllChecked, - onSelectAll, - showEventsSelect, - showSelectAllCheckbox, - sort, - tabType, - timelineId, - ]); - - const TrailingHeaderActions = useMemo(() => { - return trailingHeaderCells.map( - (Header: React.ComponentType | React.ComponentType | undefined, index) => { - const passedWidth = trailingControlColumns[index] && trailingControlColumns[index].width; - const width = passedWidth ? passedWidth : actionsColumnWidth; - return ( - - {Header && ( -
    - )} - - ); - } - ); - }, [ - trailingHeaderCells, - trailingControlColumns, - actionsColumnWidth, - browserFields, - columnHeaders, - fieldBrowserOptions, - isEventViewer, - isSelectAllChecked, - onSelectAll, - showEventsSelect, - showSelectAllCheckbox, - sort, - tabType, - timelineId, - ]); - return ( - - - {LeadingHeaderActions} - - {DroppableContent} - - {TrailingHeaderActions} - - - ); -}; - -export const ColumnHeaders = React.memo(ColumnHeadersComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/range_picker/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/range_picker/index.test.tsx deleted file mode 100644 index 4d531e34fa3c..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/range_picker/index.test.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 { mount } from 'enzyme'; -import React from 'react'; - -import { RangePicker } from '.'; -import { Ranges } from './ranges'; - -describe('RangePicker', () => { - describe('rendering', () => { - test('it renders the ranges', () => { - const wrapper = mount(); - - Ranges.forEach((range) => { - expect(wrapper.text()).toContain(range); - }); - }); - - test('it selects the option specified by the "selected" prop', () => { - const selected = '1 Month'; - const wrapper = mount(); - - expect(wrapper.find('select').props().value).toBe(selected); - }); - }); - - describe('#onRangeSelected', () => { - test('it invokes the onRangeSelected callback when a new range is selected', () => { - const oldSelection = '1 Week'; - const newSelection = '1 Day'; - const mockOnRangeSelected = jest.fn(); - - const wrapper = mount( - - ); - - wrapper.find('select').simulate('change', { target: { value: newSelection } }); - - expect(mockOnRangeSelected).toBeCalledWith(newSelection); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/range_picker/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/range_picker/index.tsx deleted file mode 100644 index 2eca94729aeb..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/range_picker/index.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiSelect } from '@elastic/eui'; -import React from 'react'; -import styled from 'styled-components'; - -import type { OnRangeSelected } from '../../../events'; - -import { Ranges } from './ranges'; - -interface Props { - selected: string; - onRangeSelected: OnRangeSelected; -} - -export const rangePickerWidth = 120; - -// TODO: Upgrade Eui library and use EuiSuperSelect -const SelectContainer = styled.div` - cursor: pointer; - width: ${rangePickerWidth}px; -`; - -SelectContainer.displayName = 'SelectContainer'; - -/** Renders a time range picker for the MiniMap (e.g. 1 Day, 1 Week...) */ -export const RangePicker = React.memo(({ selected, onRangeSelected }) => { - const onChange = (event: React.ChangeEvent): void => { - onRangeSelected(event.target.value); - }; - - return ( - - ({ - text: range, - }))} - onChange={onChange} - /> - - ); -}); - -RangePicker.displayName = 'RangePicker'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/range_picker/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/range_picker/translations.ts deleted file mode 100644 index 339c56f92490..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/range_picker/translations.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const ONE_DAY = i18n.translate('xpack.securitySolution.timeline.rangePicker.oneDay', { - defaultMessage: '1 Day', -}); - -export const ONE_WEEK = i18n.translate('xpack.securitySolution.timeline.rangePicker.oneWeek', { - defaultMessage: '1 Week', -}); - -export const ONE_MONTH = i18n.translate('xpack.securitySolution.timeline.rangePicker.oneMonth', { - defaultMessage: '1 Month', -}); - -export const ONE_YEAR = i18n.translate('xpack.securitySolution.timeline.rangePicker.oneYear', { - defaultMessage: '1 Year', -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/text_filter/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/text_filter/__snapshots__/index.test.tsx.snap deleted file mode 100644 index fc4bd7bbd614..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/text_filter/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,11 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`TextFilter rendering renders correctly against snapshot 1`] = ` - -`; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/text_filter/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/text_filter/index.test.tsx deleted file mode 100644 index aae979c19902..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/text_filter/index.test.tsx +++ /dev/null @@ -1,79 +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 { mount, shallow } from 'enzyme'; -import React from 'react'; - -import { DEFAULT_PLACEHOLDER, TextFilter } from '.'; - -describe('TextFilter', () => { - describe('rendering', () => { - test('renders correctly against snapshot', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); - - describe('placeholder', () => { - test('it renders the default placeholder when no filter is specified, and a placeholder is NOT provided', () => { - const wrapper = mount(); - - expect(wrapper.find(`input[placeholder="${DEFAULT_PLACEHOLDER}"]`).exists()).toEqual(true); - }); - - test('it renders the default placeholder when no filter is specified, a placeholder is provided', () => { - const placeholder = 'Make a jazz noise here'; - const wrapper = mount( - - ); - - expect(wrapper.find(`input[placeholder="${placeholder}"]`).exists()).toEqual(true); - }); - }); - - describe('minWidth', () => { - test('it applies the value of the minwidth prop to the input', () => { - const minWidth = 150; - const wrapper = mount(); - - expect(wrapper.find('input').props()).toHaveProperty('minwidth', `${minWidth}px`); - }); - }); - - describe('value', () => { - test('it renders the value of the filter prop', () => { - const filter = 'out the noise'; - const wrapper = mount(); - - expect(wrapper.find('input').prop('value')).toEqual(filter); - }); - }); - - describe('#onFilterChange', () => { - test('it invokes the onFilterChange callback when the input is updated', () => { - const columnId = 'foo'; - const oldFilter = 'abcdef'; - const newFilter = `${oldFilter}g`; - const onFilterChange = jest.fn(); - - const wrapper = mount( - - ); - - wrapper.find('input').simulate('change', { target: { value: newFilter } }); - expect(onFilterChange).toBeCalledWith({ - columnId, - filter: newFilter, - }); - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/text_filter/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/text_filter/index.tsx deleted file mode 100644 index d22e2ca40ca4..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/text_filter/index.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 { EuiFieldText } from '@elastic/eui'; -import { noop } from 'lodash/fp'; -import React from 'react'; -import styled from 'styled-components'; - -import type { OnFilterChange } from '../../../events'; -import type { ColumnId } from '../../column_id'; - -interface Props { - columnId: ColumnId; - filter?: string; - minWidth: number; - onFilterChange?: OnFilterChange; - placeholder?: string; -} - -export const DEFAULT_PLACEHOLDER = 'Filter'; - -const FieldText = styled(EuiFieldText)<{ minwidth: string }>` - min-width: ${(props) => props.minwidth}; -`; - -FieldText.displayName = 'FieldText'; - -/** Renders a text-based column filter */ -export const TextFilter = React.memo( - ({ - columnId, - minWidth, - filter = '', - onFilterChange = noop, - placeholder = DEFAULT_PLACEHOLDER, - }) => { - const onChange = (event: React.ChangeEvent): void => { - onFilterChange({ columnId, filter: event.target.value }); - }; - - return ( - - ); - } -); - -TextFilter.displayName = 'TextFilter'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/__snapshots__/index.test.tsx.snap deleted file mode 100644 index fd4566ca440e..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,1037 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Columns it renders the expected columns 1`] = ` - - - - - - - - - -`; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.test.tsx deleted file mode 100644 index 67f3c35a3ec1..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.test.tsx +++ /dev/null @@ -1,93 +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 { shallow } from 'enzyme'; - -import React from 'react'; - -import { DefaultCellRenderer } from '../../cell_rendering/default_cell_renderer'; -import { mockTimelineData } from '../../../../../common/mock'; -import { defaultHeaders } from '../column_headers/default_headers'; -import { getDefaultControlColumn } from '../control_columns'; - -import { DataDrivenColumns, getMappedNonEcsValue } from '.'; - -describe('Columns', () => { - const headersSansTimestamp = defaultHeaders.filter((h) => h.id !== '@timestamp'); - const ACTION_BUTTON_COUNT = 4; - const leadingControlColumns = getDefaultControlColumn(ACTION_BUTTON_COUNT); - - test('it renders the expected columns', () => { - const wrapper = shallow( - - ); - - expect(wrapper).toMatchSnapshot(); - }); - - describe('getMappedNonEcsValue', () => { - const existingField = 'Descarte'; - const existingValue = ['IThinkThereforeIAm']; - - test('should return the value if the fieldName is found', () => { - const result = getMappedNonEcsValue({ - data: [{ field: existingField, value: existingValue }], - fieldName: existingField, - }); - - expect(result).toBe(existingValue); - }); - - test('should return undefined if the value cannot be found in the array', () => { - const result = getMappedNonEcsValue({ - data: [{ field: existingField, value: existingValue }], - fieldName: 'nonExistent', - }); - - expect(result).toBeUndefined(); - }); - - test('should return undefined when data is an empty array', () => { - const result = getMappedNonEcsValue({ data: [], fieldName: existingField }); - - expect(result).toBeUndefined(); - }); - - test('should return undefined when data is undefined', () => { - const result = getMappedNonEcsValue({ data: undefined, fieldName: existingField }); - - expect(result).toBeUndefined(); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.tsx deleted file mode 100644 index a1d65e69dba5..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/index.tsx +++ /dev/null @@ -1,472 +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 { EuiScreenReaderOnly } from '@elastic/eui'; -import React, { useMemo } from 'react'; -import { getOr } from 'lodash/fp'; -import { DRAGGABLE_KEYBOARD_WRAPPER_CLASS_NAME } from '@kbn/securitysolution-t-grid'; - -import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; -import type { - SetEventsDeleted, - SetEventsLoading, - ActionProps, - ControlColumnProps, - RowCellRender, -} from '../../../../../../common/types'; -import type { - CellValueElementProps, - ColumnHeaderOptions, - TimelineTabs, -} from '../../../../../../common/types/timeline'; -import type { TimelineNonEcsData } from '../../../../../../common/search_strategy/timeline'; -import { ARIA_COLUMN_INDEX_OFFSET } from '../../helpers'; -import type { OnRowSelected } from '../../events'; -import type { inputsModel } from '../../../../../common/store'; -import { - EventsTd, - EVENTS_TD_CLASS_NAME, - EventsTdContent, - EventsTdGroupData, - EventsTdGroupActions, -} from '../../styles'; - -import { StatefulCell } from './stateful_cell'; -import * as i18n from './translations'; - -interface CellProps { - _id: string; - ariaRowindex: number; - index: number; - header: ColumnHeaderOptions; - data: TimelineNonEcsData[]; - ecsData: Ecs; - hasRowRenderers: boolean; - notesCount: number; - renderCellValue: (props: CellValueElementProps) => React.ReactNode; - tabType?: TimelineTabs; - timelineId: string; -} - -interface DataDrivenColumnProps { - id: string; - actionsColumnWidth: number; - ariaRowindex: number; - checked: boolean; - columnHeaders: ColumnHeaderOptions[]; - columnValues: string; - data: TimelineNonEcsData[]; - ecsData: Ecs; - eventIdToNoteIds: Readonly>; - isEventPinned: boolean; - isEventViewer?: boolean; - loadingEventIds: Readonly; - notesCount: number; - onEventDetailsPanelOpened: () => void; - onRowSelected: OnRowSelected; - refetch: inputsModel.Refetch; - onRuleChange?: () => void; - hasRowRenderers: boolean; - selectedEventIds: Readonly>; - showCheckboxes: boolean; - showNotes: boolean; - renderCellValue: (props: CellValueElementProps) => React.ReactNode; - tabType?: TimelineTabs; - timelineId: string; - toggleShowNotes: () => void; - trailingControlColumns: ControlColumnProps[]; - leadingControlColumns: ControlColumnProps[]; - setEventsLoading: SetEventsLoading; - setEventsDeleted: SetEventsDeleted; -} - -const SPACE = ' '; - -export const shouldForwardKeyDownEvent = (key: string): boolean => { - switch (key) { - case SPACE: // fall through - case 'Enter': - return true; - default: - return false; - } -}; - -export const onKeyDown = (keyboardEvent: React.KeyboardEvent) => { - const { altKey, ctrlKey, key, metaKey, shiftKey, target, type } = keyboardEvent; - - const targetElement = target as Element; - - // we *only* forward the event to the (child) draggable keyboard wrapper - // if the keyboard event originated from the container (TD) element - if (shouldForwardKeyDownEvent(key) && targetElement.className?.includes(EVENTS_TD_CLASS_NAME)) { - const draggableKeyboardWrapper = targetElement.querySelector( - `.${DRAGGABLE_KEYBOARD_WRAPPER_CLASS_NAME}` - ); - - const newEvent = new KeyboardEvent(type, { - altKey, - bubbles: true, - cancelable: true, - ctrlKey, - key, - metaKey, - shiftKey, - }); - - if (key === ' ') { - // prevent the default behavior of scrolling the table when space is pressed - keyboardEvent.preventDefault(); - } - - draggableKeyboardWrapper?.dispatchEvent(newEvent); - } -}; - -const TgridActionTdCell = ({ - action: Action, - width, - actionsColumnWidth, - ariaRowindex, - columnId, - columnValues, - data, - ecsData, - eventIdToNoteIds, - index, - isEventPinned, - isEventViewer, - eventId, - loadingEventIds, - notesCount, - onEventDetailsPanelOpened, - onRowSelected, - refetch, - rowIndex, - hasRowRenderers, - onRuleChange, - selectedEventIds, - showCheckboxes, - showNotes, - tabType, - timelineId, - toggleShowNotes, - setEventsLoading, - setEventsDeleted, -}: ActionProps & { - columnId: string; - hasRowRenderers: boolean; - actionsColumnWidth: number; - notesCount: number; - selectedEventIds: Readonly>; -}) => { - const displayWidth = width ? width : actionsColumnWidth; - return ( - - - - <> - -

    {i18n.YOU_ARE_IN_A_TABLE_CELL({ row: ariaRowindex, column: index + 2 })}

    -
    - {Action && ( - - )} - -
    - {hasRowRenderers ? ( - -

    {i18n.EVENT_HAS_AN_EVENT_RENDERER(ariaRowindex)}

    -
    - ) : null} - - {notesCount ? ( - -

    {i18n.EVENT_HAS_NOTES({ row: ariaRowindex, notesCount })}

    -
    - ) : null} -
    -
    - ); -}; - -const TgridTdCell = ({ - _id, - ariaRowindex, - index, - header, - data, - ecsData, - hasRowRenderers, - notesCount, - renderCellValue, - tabType, - timelineId, -}: CellProps) => { - const ariaColIndex = index + ARIA_COLUMN_INDEX_OFFSET; - return ( - - - <> - -

    {i18n.YOU_ARE_IN_A_TABLE_CELL({ row: ariaRowindex, column: ariaColIndex })}

    -
    - - -
    - {hasRowRenderers ? ( - -

    {i18n.EVENT_HAS_AN_EVENT_RENDERER(ariaRowindex)}

    -
    - ) : null} - - {notesCount ? ( - -

    {i18n.EVENT_HAS_NOTES({ row: ariaRowindex, notesCount })}

    -
    - ) : null} -
    - ); -}; - -export const DataDrivenColumns = React.memo( - ({ - ariaRowindex, - actionsColumnWidth, - columnHeaders, - columnValues, - data, - ecsData, - eventIdToNoteIds, - isEventPinned, - isEventViewer, - id: _id, - loadingEventIds, - notesCount, - onEventDetailsPanelOpened, - onRowSelected, - refetch, - hasRowRenderers, - onRuleChange, - renderCellValue, - selectedEventIds, - showCheckboxes, - showNotes, - tabType, - timelineId, - toggleShowNotes, - trailingControlColumns, - leadingControlColumns, - setEventsLoading, - setEventsDeleted, - }) => { - const trailingActionCells = useMemo( - () => - trailingControlColumns ? trailingControlColumns.map((column) => column.rowCellRender) : [], - [trailingControlColumns] - ); - const leadingAndDataColumnCount = useMemo( - () => leadingControlColumns.length + columnHeaders.length, - [leadingControlColumns, columnHeaders] - ); - const TrailingActions = useMemo( - () => - trailingActionCells.map((Action: RowCellRender | undefined, index) => { - return ( - Action && ( - - ) - ); - }), - [ - trailingControlColumns, - _id, - data, - ecsData, - onRowSelected, - isEventPinned, - isEventViewer, - actionsColumnWidth, - ariaRowindex, - columnValues, - eventIdToNoteIds, - hasRowRenderers, - leadingAndDataColumnCount, - loadingEventIds, - notesCount, - onEventDetailsPanelOpened, - onRuleChange, - refetch, - selectedEventIds, - showCheckboxes, - showNotes, - tabType, - timelineId, - toggleShowNotes, - trailingActionCells, - setEventsLoading, - setEventsDeleted, - ] - ); - const ColumnHeaders = useMemo( - () => - columnHeaders.map((header, index) => ( - - )), - [ - _id, - ariaRowindex, - columnHeaders, - data, - ecsData, - hasRowRenderers, - notesCount, - renderCellValue, - tabType, - timelineId, - ] - ); - return ( - - {ColumnHeaders} - {TrailingActions} - - ); - } -); - -DataDrivenColumns.displayName = 'DataDrivenColumns'; - -export const getMappedNonEcsValue = ({ - data, - fieldName, -}: { - data?: TimelineNonEcsData[]; - fieldName: string; -}): string[] | undefined => { - /* - While data _should_ always be defined - There is the potential for race conditions where a component using this function - is still visible in the UI, while the data has since been removed. - To cover all scenarios where this happens we'll check for the presence of data here - */ - if (!data || data.length === 0) return undefined; - const item = data.find((d) => d.field === fieldName); - if (item != null && item.value != null) { - return item.value; - } - return undefined; -}; - -export const useGetMappedNonEcsValue = ({ - data, - fieldName, -}: { - data?: TimelineNonEcsData[]; - fieldName: string; -}): string[] | undefined => { - return useMemo(() => getMappedNonEcsValue({ data, fieldName }), [data, fieldName]); -}; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.test.tsx deleted file mode 100644 index 32ca51ca62f7..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.test.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 { mount } from 'enzyme'; -import { cloneDeep } from 'lodash/fp'; -import React, { useEffect } from 'react'; - -import { defaultHeaders, mockTimelineData } from '../../../../../common/mock'; -import type { TimelineNonEcsData } from '../../../../../../common/search_strategy/timeline'; -import type { - ColumnHeaderOptions, - CellValueElementProps, -} from '../../../../../../common/types/timeline'; -import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline'; - -import { StatefulCell } from './stateful_cell'; -import { useGetMappedNonEcsValue } from '.'; - -/** - * This (test) component implement's `EuiDataGrid`'s `renderCellValue` interface, - * as documented here: https://elastic.github.io/eui/#/tabular-content/data-grid - * - * Its `CellValueElementProps` props are a superset of `EuiDataGridCellValueElementProps`. - * The `setCellProps` function, defined by the `EuiDataGridCellValueElementProps` interface, - * is typically called in a `useEffect`, as illustrated by `EuiDataGrid`'s code sandbox example: - * https://codesandbox.io/s/zhxmo - */ -const RenderCellValue: React.FC = ({ columnId, data, setCellProps }) => { - const value = useGetMappedNonEcsValue({ - data, - fieldName: columnId, - }); - useEffect(() => { - // branching logic that conditionally renders a specific cell green: - if (columnId === defaultHeaders[0].id) { - if (value?.length) { - setCellProps({ - style: { - backgroundColor: 'green', - }, - }); - } - } - }, [columnId, data, setCellProps, value]); - - return
    {value}
    ; -}; - -describe('StatefulCell', () => { - const rowIndex = 123; - const colIndex = 0; - const eventId = '_id-123'; - const linkValues = ['foo', 'bar', '@baz']; - const timelineId = TimelineId.test; - - let header: ColumnHeaderOptions; - let data: TimelineNonEcsData[]; - beforeEach(() => { - data = cloneDeep(mockTimelineData[0].data); - header = cloneDeep(defaultHeaders[0]); - }); - - test('it invokes renderCellValue with the expected arguments when tabType is specified', () => { - const renderCellValue = jest.fn(); - - mount( - - ); - - expect(renderCellValue).toBeCalledWith( - expect.objectContaining({ - columnId: header.id, - eventId, - data, - header, - isExpandable: true, - isExpanded: false, - isDetails: false, - linkValues, - rowIndex, - colIndex, - scopeId: timelineId, - }) - ); - }); - - test('it invokes renderCellValue with the expected arguments when tabType is NOT specified', () => { - const renderCellValue = jest.fn(); - - mount( - - ); - - expect(renderCellValue).toBeCalledWith( - expect.objectContaining({ - columnId: header.id, - eventId, - data, - header, - isExpandable: true, - isExpanded: false, - isDetails: false, - linkValues, - rowIndex, - colIndex, - scopeId: timelineId, - }) - ); - }); - - test('it renders the React.Node returned by renderCellValue', () => { - const renderCellValue = () =>
    ; - - const wrapper = mount( - - ); - - expect(wrapper.find('[data-test-subj="renderCellValue"]').exists()).toBe(true); - }); - - test("it renders a div with the styles set by `renderCellValue`'s `setCellProps` argument", () => { - const wrapper = mount( - - ); - - expect( - wrapper.find('[data-test-subj="statefulCell"]').getDOMNode().getAttribute('style') - ).toEqual('background-color: green;'); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.tsx deleted file mode 100644 index 941f6499fe85..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/stateful_cell.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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { HTMLAttributes } from 'react'; -import React, { useState } from 'react'; - -import type { TimelineNonEcsData } from '../../../../../../common/search_strategy/timeline'; -import type { - ColumnHeaderOptions, - CellValueElementProps, - TimelineTabs, -} from '../../../../../../common/types/timeline'; - -export interface CommonProps { - className?: string; - 'aria-label'?: string; - 'data-test-subj'?: string; -} - -const StatefulCellComponent = ({ - rowIndex, - colIndex, - data, - header, - eventId, - linkValues, - renderCellValue, - tabType, - timelineId, -}: { - rowIndex: number; - colIndex: number; - data: TimelineNonEcsData[]; - header: ColumnHeaderOptions; - eventId: string; - linkValues: string[] | undefined; - renderCellValue: (props: CellValueElementProps) => React.ReactNode; - tabType?: TimelineTabs; - timelineId: string; -}) => { - const [cellProps, setCellProps] = useState>({}); - return ( -
    - {renderCellValue({ - columnId: header.id, - eventId, - data, - header, - isDraggable: true, - isExpandable: true, - isExpanded: false, - isDetails: false, - isTimeline: true, - linkValues, - rowIndex, - colIndex, - setCellProps, - scopeId: timelineId, - key: tabType != null ? `${timelineId}-${tabType}` : timelineId, - })} -
    - ); -}; - -StatefulCellComponent.displayName = 'StatefulCellComponent'; - -export const StatefulCell = React.memo(StatefulCellComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/translations.ts deleted file mode 100644 index 18bd7a600f7c..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/data_driven_columns/translations.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const YOU_ARE_IN_A_TABLE_CELL = ({ column, row }: { column: number; row: number }) => - i18n.translate('xpack.securitySolution.timeline.youAreInATableCellScreenReaderOnly', { - values: { column, row }, - defaultMessage: 'You are in a table cell. row: {row}, column: {column}', - }); - -export const EVENT_HAS_AN_EVENT_RENDERER = (row: number) => - i18n.translate('xpack.securitySolution.timeline.eventHasEventRendererScreenReaderOnly', { - values: { row }, - defaultMessage: - 'The event in row {row} has an event renderer. Press shift + down arrow to focus it.', - }); - -export const EVENT_HAS_NOTES = ({ notesCount, row }: { notesCount: number; row: number }) => - i18n.translate('xpack.securitySolution.timeline.eventHasNotesScreenReaderOnly', { - values: { notesCount, row }, - defaultMessage: - 'The event in row {row} has {notesCount, plural, =1 {a note} other {{notesCount} notes}}. Press shift + right arrow to focus notes.', - }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.test.tsx deleted file mode 100644 index 8b49c12eaf73..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.test.tsx +++ /dev/null @@ -1,164 +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 { mount, type ComponentType as EnzymeComponentType } from 'enzyme'; -import React from 'react'; - -import { TestProviders } from '../../../../../common/mock'; - -import { EventColumnView } from './event_column_view'; -import { DefaultCellRenderer } from '../../cell_rendering/default_cell_renderer'; -import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline'; -import { TimelineTypeEnum } from '../../../../../../common/api/timeline'; -import { useShallowEqualSelector } from '../../../../../common/hooks/use_selector'; -import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; -import { getDefaultControlColumn } from '../control_columns'; -import { testLeadingControlColumn } from '../../../../../common/mock/mock_timeline_control_columns'; -import { mockTimelines } from '../../../../../common/mock/mock_timelines_plugin'; -import { mockCasesContract } from '@kbn/cases-plugin/public/mocks'; -import { getActionsColumnWidth } from '../../../../../common/components/header_actions'; - -jest.mock('../../../../../common/components/header_actions/add_note_icon_item', () => { - return { - AddEventNoteAction: jest.fn(() =>
    ), - }; -}); - -jest.mock('../../../../../common/hooks/use_experimental_features'); -const useIsExperimentalFeatureEnabledMock = useIsExperimentalFeatureEnabled as jest.Mock; -jest.mock('../../../../../common/hooks/use_selector', () => ({ - useShallowEqualSelector: jest.fn(), - useDeepEqualSelector: jest.fn(), -})); -jest.mock('../../../../../common/components/user_privileges', () => { - return { - useUserPrivileges: () => ({ - listPrivileges: { loading: false, error: undefined, result: undefined }, - detectionEnginePrivileges: { loading: false, error: undefined, result: undefined }, - endpointPrivileges: {}, - kibanaSecuritySolutionsPrivileges: { crud: true, read: true }, - }), - }; -}); -jest.mock('../../../../../common/components/guided_onboarding_tour/tour_step'); -jest.mock('../../../../../common/lib/kibana', () => { - const originalModule = jest.requireActual('../../../../../common/lib/kibana'); - - return { - ...originalModule, - useKibana: () => ({ - services: { - timelines: { ...mockTimelines }, - data: { - search: jest.fn(), - query: jest.fn(), - }, - application: { - capabilities: { - siem: { crud_alerts: true, read_alerts: true }, - }, - }, - cases: mockCasesContract(), - }, - }), - useNavigateTo: () => ({ - navigateTo: jest.fn(), - }), - useToasts: jest.fn().mockReturnValue({ - addError: jest.fn(), - addSuccess: jest.fn(), - addWarning: jest.fn(), - remove: jest.fn(), - }), - }; -}); - -describe('EventColumnView', () => { - useIsExperimentalFeatureEnabledMock.mockReturnValue(false); - (useShallowEqualSelector as jest.Mock).mockReturnValue(TimelineTypeEnum.default); - const ACTION_BUTTON_COUNT = 4; - const leadingControlColumns = getDefaultControlColumn(ACTION_BUTTON_COUNT); - - const props = { - ariaRowindex: 2, - id: 'event-id', - actionsColumnWidth: getActionsColumnWidth(ACTION_BUTTON_COUNT), - associateNote: jest.fn(), - columnHeaders: [], - columnRenderers: [], - data: [ - { - field: 'host.name', - }, - ], - ecsData: { - _id: 'id', - }, - eventIdToNoteIds: {}, - expanded: false, - hasRowRenderers: false, - loading: false, - loadingEventIds: [], - notesCount: 0, - onEventDetailsPanelOpened: jest.fn(), - onRowSelected: jest.fn(), - refetch: jest.fn(), - renderCellValue: DefaultCellRenderer, - selectedEventIds: {}, - showCheckboxes: false, - showNotes: false, - tabType: TimelineTabs.query, - timelineId: TimelineId.active, - toggleShowNotes: jest.fn(), - updateNote: jest.fn(), - isEventPinned: false, - leadingControlColumns, - trailingControlColumns: [], - setEventsLoading: jest.fn(), - setEventsDeleted: jest.fn(), - }; - - test('it does NOT render a notes button when isEventsViewer is true', () => { - const wrapper = mount(, { - wrappingComponent: TestProviders as EnzymeComponentType<{}>, - }); - - expect(wrapper.find('[data-test-subj="add-note-button-mock"]').exists()).toBe(false); - }); - - test('it does NOT render a notes button when showNotes is false', () => { - const wrapper = mount(, { - wrappingComponent: TestProviders as EnzymeComponentType<{}>, - }); - - expect(wrapper.find('[data-test-subj="add-note-button-mock"]').exists()).toBe(false); - }); - - test('it does NOT render a pin button when isEventViewer is true', () => { - const wrapper = mount(, { - wrappingComponent: TestProviders as EnzymeComponentType<{}>, - }); - - expect(wrapper.find('[data-test-subj="pin"]').exists()).toBe(false); - }); - - test('it renders a custom control column in addition to the default control column', () => { - const wrapper = mount( - , - { - wrappingComponent: TestProviders as EnzymeComponentType<{}>, - } - ); - - expect(wrapper.find('[data-test-subj="expand-event"]').exists()).toBeTruthy(); - expect(wrapper.find('[data-test-subj="test-body-control-column-cell"]').exists()).toBeTruthy(); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx deleted file mode 100644 index e184e27d428e..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/event_column_view.tsx +++ /dev/null @@ -1,225 +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, { useMemo } from 'react'; - -import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; -import type { - ControlColumnProps, - RowCellRender, - SetEventsDeleted, - SetEventsLoading, -} from '../../../../../../common/types'; -import type { TimelineNonEcsData } from '../../../../../../common/search_strategy/timeline'; -import type { OnRowSelected } from '../../events'; -import { EventsTrData, EventsTdGroupActions } from '../../styles'; -import { DataDrivenColumns, getMappedNonEcsValue } from '../data_driven_columns'; -import type { inputsModel } from '../../../../../common/store'; -import type { - ColumnHeaderOptions, - CellValueElementProps, - TimelineTabs, -} from '../../../../../../common/types/timeline'; - -interface Props { - id: string; - actionsColumnWidth: number; - ariaRowindex: number; - columnHeaders: ColumnHeaderOptions[]; - data: TimelineNonEcsData[]; - ecsData: Ecs; - eventIdToNoteIds: Readonly>; - isEventPinned: boolean; - isEventViewer?: boolean; - loadingEventIds: Readonly; - notesCount: number; - onEventDetailsPanelOpened: () => void; - onRowSelected: OnRowSelected; - refetch: inputsModel.Refetch; - renderCellValue: (props: CellValueElementProps) => React.ReactNode; - onRuleChange?: () => void; - hasRowRenderers: boolean; - selectedEventIds: Readonly>; - showCheckboxes: boolean; - showNotes: boolean; - tabType?: TimelineTabs; - timelineId: string; - toggleShowNotes: (eventId?: string) => void; - leadingControlColumns: ControlColumnProps[]; - trailingControlColumns: ControlColumnProps[]; - setEventsLoading: SetEventsLoading; - setEventsDeleted: SetEventsDeleted; -} - -export const EventColumnView = React.memo( - ({ - id, - actionsColumnWidth, - ariaRowindex, - columnHeaders, - data, - ecsData, - eventIdToNoteIds, - isEventPinned = false, - isEventViewer = false, - loadingEventIds, - notesCount, - onEventDetailsPanelOpened, - onRowSelected, - refetch, - hasRowRenderers, - onRuleChange, - renderCellValue, - selectedEventIds, - showCheckboxes, - showNotes, - tabType, - timelineId, - toggleShowNotes, - leadingControlColumns, - trailingControlColumns, - setEventsLoading, - setEventsDeleted, - }) => { - // Each action button shall announce itself to screen readers via an `aria-label` - // in the following format: - // "button description, for the event in row {ariaRowindex}, with columns {columnValues}", - // so we combine the column values here: - const columnValues = useMemo( - () => - columnHeaders - .map( - (header) => - getMappedNonEcsValue({ - data, - fieldName: header.id, - }) ?? [] - ) - .join(' '), - [columnHeaders, data] - ); - - const leadingActionCells = useMemo( - () => - leadingControlColumns ? leadingControlColumns.map((column) => column.rowCellRender) : [], - [leadingControlColumns] - ); - const LeadingActions = useMemo( - () => - leadingActionCells.map((Action: RowCellRender | undefined, index) => { - const width = leadingControlColumns[index].width - ? leadingControlColumns[index].width - : actionsColumnWidth; - return ( - - {Action && ( - - )} - - ); - }), - [ - actionsColumnWidth, - ariaRowindex, - columnValues, - data, - ecsData, - eventIdToNoteIds, - id, - isEventPinned, - isEventViewer, - leadingActionCells, - leadingControlColumns, - loadingEventIds, - onEventDetailsPanelOpened, - onRowSelected, - onRuleChange, - refetch, - selectedEventIds, - showCheckboxes, - tabType, - timelineId, - toggleShowNotes, - setEventsLoading, - setEventsDeleted, - showNotes, - ] - ); - return ( - - {LeadingActions} - - - ); - } -); - -EventColumnView.displayName = 'EventColumnView'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/index.tsx deleted file mode 100644 index 76c28f24b14d..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/index.tsx +++ /dev/null @@ -1,111 +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 { isEmpty } from 'lodash'; - -import type { ControlColumnProps } from '../../../../../../common/types'; -import type { inputsModel } from '../../../../../common/store'; -import type { - TimelineItem, - TimelineNonEcsData, -} from '../../../../../../common/search_strategy/timeline'; -import type { - ColumnHeaderOptions, - CellValueElementProps, - RowRenderer, - TimelineTabs, -} from '../../../../../../common/types/timeline'; -import type { OnRowSelected } from '../../events'; -import { EventsTbody } from '../../styles'; -import { StatefulEvent } from './stateful_event'; -import { eventIsPinned } from '../helpers'; - -/** This offset begins at two, because the header row counts as "row 1", and aria-rowindex starts at "1" */ -const ARIA_ROW_INDEX_OFFSET = 2; - -interface Props { - actionsColumnWidth: number; - columnHeaders: ColumnHeaderOptions[]; - containerRef: React.MutableRefObject; - data: TimelineItem[]; - eventIdToNoteIds: Readonly>; - id: string; - isEventViewer?: boolean; - lastFocusedAriaColindex: number; - loadingEventIds: Readonly; - onRowSelected: OnRowSelected; - pinnedEventIds: Readonly>; - refetch: inputsModel.Refetch; - renderCellValue: (props: CellValueElementProps) => React.ReactNode; - onRuleChange?: () => void; - rowRenderers: RowRenderer[]; - selectedEventIds: Readonly>; - showCheckboxes: boolean; - tabType?: TimelineTabs; - leadingControlColumns: ControlColumnProps[]; - trailingControlColumns: ControlColumnProps[]; - onToggleShowNotes?: (eventId?: string) => void; -} - -const EventsComponent: React.FC = ({ - actionsColumnWidth, - columnHeaders, - containerRef, - data, - eventIdToNoteIds, - id, - isEventViewer = false, - lastFocusedAriaColindex, - loadingEventIds, - onRowSelected, - pinnedEventIds, - refetch, - onRuleChange, - renderCellValue, - rowRenderers, - selectedEventIds, - showCheckboxes, - tabType, - leadingControlColumns, - trailingControlColumns, - onToggleShowNotes, -}) => ( - - {data.map((event, i) => ( - - ))} - -); - -export const Events = React.memo(EventsComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx deleted file mode 100644 index 05f7a9d8b8e2..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/events/stateful_event.tsx +++ /dev/null @@ -1,266 +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 { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import type { PropsWithChildren } from 'react'; -import React, { useCallback, useMemo, useRef, useState } from 'react'; -import { useDispatch } from 'react-redux'; -import { isEventBuildingBlockType } from '@kbn/securitysolution-data-table'; -import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { DocumentDetailsRightPanelKey } from '../../../../../flyout/document_details/shared/constants/panel_keys'; -import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector'; -import { useKibana } from '../../../../../common/lib/kibana'; -import type { - ColumnHeaderOptions, - CellValueElementProps, - RowRenderer, - TimelineTabs, -} from '../../../../../../common/types/timeline'; -import type { - TimelineItem, - TimelineNonEcsData, -} from '../../../../../../common/search_strategy/timeline'; -import type { OnRowSelected } from '../../events'; -import { STATEFUL_EVENT_CSS_CLASS_NAME } from '../../helpers'; -import { EventsTrGroup, EventsTrSupplement, EventsTrSupplementContainer } from '../../styles'; -import { getEventType, isEvenEqlSequence } from '../helpers'; -import { useEventDetailsWidthContext } from '../../../../../common/components/events_viewer/event_details_width_context'; -import { EventColumnView } from './event_column_view'; -import type { inputsModel } from '../../../../../common/store'; -import { appSelectors } from '../../../../../common/store'; -import { timelineActions } from '../../../../store'; -import type { TimelineResultNote } from '../../../open_timeline/types'; -import { getRowRenderer } from '../renderers/get_row_renderer'; -import { StatefulRowRenderer } from './stateful_row_renderer'; -import { NOTES_BUTTON_CLASS_NAME } from '../../properties/helpers'; -import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; -import type { - ControlColumnProps, - SetEventsDeleted, - SetEventsLoading, -} from '../../../../../../common/types'; - -interface Props { - actionsColumnWidth: number; - containerRef: React.MutableRefObject; - columnHeaders: ColumnHeaderOptions[]; - event: TimelineItem; - eventIdToNoteIds: Readonly>; - isEventViewer?: boolean; - lastFocusedAriaColindex: number; - loadingEventIds: Readonly; - onRowSelected: OnRowSelected; - isEventPinned: boolean; - refetch: inputsModel.Refetch; - ariaRowindex: number; - onRuleChange?: () => void; - renderCellValue: (props: CellValueElementProps) => React.ReactNode; - rowRenderers: RowRenderer[]; - selectedEventIds: Readonly>; - showCheckboxes: boolean; - tabType?: TimelineTabs; - timelineId: string; - leadingControlColumns: ControlColumnProps[]; - trailingControlColumns: ControlColumnProps[]; - onToggleShowNotes?: (eventId?: string) => void; -} - -const emptyNotes: string[] = []; - -const EventsTrSupplementContainerWrapper = React.memo>( - ({ children }) => { - const width = useEventDetailsWidthContext(); - return {children}; - } -); - -EventsTrSupplementContainerWrapper.displayName = 'EventsTrSupplementContainerWrapper'; - -const StatefulEventComponent: React.FC = ({ - actionsColumnWidth, - containerRef, - columnHeaders, - event, - eventIdToNoteIds, - isEventViewer = false, - isEventPinned = false, - lastFocusedAriaColindex, - loadingEventIds, - onRowSelected, - refetch, - renderCellValue, - rowRenderers, - onRuleChange, - ariaRowindex, - selectedEventIds, - showCheckboxes, - tabType, - timelineId, - leadingControlColumns, - trailingControlColumns, - onToggleShowNotes, -}) => { - const { telemetry } = useKibana().services; - const trGroupRef = useRef(null); - const dispatch = useDispatch(); - - const { openFlyout } = useExpandableFlyoutApi(); - - // Store context in state rather than creating object in provider value={} to prevent re-renders caused by a new object being created - const [activeStatefulEventContext] = useState({ - timelineID: timelineId, - enableHostDetailsFlyout: true, - enableIpDetailsFlyout: true, - tabType, - }); - - const [, setFocusedNotes] = useState<{ [eventId: string]: boolean }>({}); - - const eventId = event._id; - - const isDetailPanelExpanded: boolean = false; - - const getNotesByIds = useMemo(() => appSelectors.notesByIdsSelector(), []); - const notesById = useDeepEqualSelector(getNotesByIds); - const noteIds: string[] = eventIdToNoteIds[eventId] || emptyNotes; - - const notes: TimelineResultNote[] = useMemo( - () => - appSelectors.getNotes(notesById, noteIds).map((note) => ({ - savedObjectId: note.saveObjectId, - note: note.note, - noteId: note.id, - updated: (note.lastEdit ?? note.created).getTime(), - updatedBy: note.user, - })), - [notesById, noteIds] - ); - - const hasRowRenderers: boolean = useMemo( - () => getRowRenderer({ data: event.ecs, rowRenderers }) != null, - [event.ecs, rowRenderers] - ); - - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const indexName = event._index!; - - const onToggleShowNotesHandler = useCallback( - (currentEventId?: string) => { - onToggleShowNotes?.(currentEventId); - setFocusedNotes((prevShowNotes) => { - if (prevShowNotes[eventId]) { - // notes are closing, so focus the notes button on the next tick, after escaping the EuiFocusTrap - setTimeout(() => { - const notesButtonElement = trGroupRef.current?.querySelector( - `.${NOTES_BUTTON_CLASS_NAME}` - ); - notesButtonElement?.focus(); - }, 0); - } - - return { ...prevShowNotes, [eventId]: !prevShowNotes[eventId] }; - }); - }, - [onToggleShowNotes, eventId] - ); - - const handleOnEventDetailPanelOpened = useCallback(() => { - openFlyout({ - right: { - id: DocumentDetailsRightPanelKey, - params: { - id: eventId, - indexName, - scopeId: timelineId, - }, - }, - }); - telemetry.reportDetailsFlyoutOpened({ - location: timelineId, - panel: 'right', - }); - }, [eventId, indexName, openFlyout, timelineId, telemetry]); - - const setEventsLoading = useCallback( - ({ eventIds, isLoading }) => { - dispatch(timelineActions.setEventsLoading({ id: timelineId, eventIds, isLoading })); - }, - [dispatch, timelineId] - ); - - const setEventsDeleted = useCallback( - ({ eventIds, isDeleted }) => { - dispatch(timelineActions.setEventsDeleted({ id: timelineId, eventIds, isDeleted })); - }, - [dispatch, timelineId] - ); - - return ( - - - - - - - - - - - - - - - - ); -}; - -export const StatefulEvent = React.memo(StatefulEventComponent); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx deleted file mode 100644 index 0c365ae42798..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx +++ /dev/null @@ -1,407 +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, type ComponentType as EnzymeComponentType } from 'enzyme'; -import { waitFor } from '@testing-library/react'; - -import { useKibana, useCurrentUser } from '../../../../common/lib/kibana'; -import { DefaultCellRenderer } from '../cell_rendering/default_cell_renderer'; -import { mockBrowserFields } from '../../../../common/containers/source/mock'; -import { Direction } from '../../../../../common/search_strategy'; -import { - defaultHeaders, - mockGlobalState, - mockTimelineData, - createMockStore, - TestProviders, -} from '../../../../common/mock'; -import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; -import { useAppToastsMock } from '../../../../common/hooks/use_app_toasts.mock'; - -import type { Props } from '.'; -import { StatefulBody } from '.'; -import type { Sort } from './sort'; -import { getDefaultControlColumn } from './control_columns'; -import { TimelineId, TimelineTabs } from '../../../../../common/types/timeline'; -import { defaultRowRenderers } from './renderers'; -import type { State } from '../../../../common/store'; -import type { UseFieldBrowserOptionsProps } from '../../fields_browser'; -import type { - DraggableProvided, - DraggableStateSnapshot, - DroppableProvided, - DroppableStateSnapshot, -} from '@hello-pangea/dnd'; -import { DocumentDetailsRightPanelKey } from '../../../../flyout/document_details/shared/constants/panel_keys'; -import { createTelemetryServiceMock } from '../../../../common/lib/telemetry/telemetry_service.mock'; -import { createExpandableFlyoutApiMock } from '../../../../common/mock/expandable_flyout'; -import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; - -jest.mock('../../../../common/hooks/use_app_toasts'); -jest.mock('../../../../common/components/guided_onboarding_tour/tour_step'); -jest.mock( - '../../../../detections/components/alerts_table/timeline_actions/use_add_to_case_actions' -); - -jest.mock('../../../../common/hooks/use_upselling', () => ({ - useUpsellingMessage: jest.fn(), -})); - -jest.mock('../../../../common/components/user_privileges', () => { - return { - useUserPrivileges: () => ({ - listPrivileges: { loading: false, error: undefined, result: undefined }, - detectionEnginePrivileges: { loading: false, error: undefined, result: undefined }, - endpointPrivileges: {}, - kibanaSecuritySolutionsPrivileges: { crud: true, read: true }, - }), - }; -}); - -const mockUseFieldBrowserOptions = jest.fn(); -const mockUseKibana = useKibana as jest.Mock; -const mockUseCurrentUser = useCurrentUser as jest.Mock>>; -const mockCasesContract = jest.requireActual('@kbn/cases-plugin/public/mocks'); -jest.mock('../../fields_browser', () => ({ - useFieldBrowserOptions: (props: UseFieldBrowserOptionsProps) => mockUseFieldBrowserOptions(props), -})); - -const useAddToTimeline = () => ({ - beginDrag: jest.fn(), - cancelDrag: jest.fn(), - dragToLocation: jest.fn(), - endDrag: jest.fn(), - hasDraggableLock: jest.fn(), - startDragToTimeline: jest.fn(), -}); - -jest.mock('../../../../common/lib/kibana'); -const mockSort: Sort[] = [ - { - columnId: '@timestamp', - columnType: 'date', - esTypes: ['date'], - sortDirection: Direction.desc, - }, -]; - -const mockDispatch = jest.fn(); -jest.mock('react-redux', () => { - const original = jest.requireActual('react-redux'); - - return { - ...original, - useDispatch: () => mockDispatch, - }; -}); - -const mockOpenFlyout = jest.fn(); -jest.mock('@kbn/expandable-flyout'); - -const mockedTelemetry = createTelemetryServiceMock(); - -jest.mock('../../../../common/components/link_to', () => { - const originalModule = jest.requireActual('../../../../common/components/link_to'); - return { - ...originalModule, - useGetSecuritySolutionUrl: () => - jest.fn(({ deepLinkId }: { deepLinkId: string }) => `/${deepLinkId}`), - useNavigateTo: () => { - return { navigateTo: jest.fn() }; - }, - useAppUrl: () => { - return { getAppUrl: jest.fn() }; - }, - }; -}); - -jest.mock('../../../../common/components/links', () => { - const originalModule = jest.requireActual('../../../../common/components/links'); - return { - ...originalModule, - useGetSecuritySolutionUrl: () => - jest.fn(({ deepLinkId }: { deepLinkId: string }) => `/${deepLinkId}`), - useNavigateTo: () => { - return { navigateTo: jest.fn() }; - }, - useAppUrl: () => { - return { getAppUrl: jest.fn() }; - }, - }; -}); - -// Prevent Resolver from rendering -jest.mock('../../graph_overlay'); - -jest.mock('../../fields_browser/create_field_button', () => ({ - useCreateFieldButton: () => <>, -})); - -jest.mock('@elastic/eui', () => { - const original = jest.requireActual('@elastic/eui'); - return { - ...original, - EuiScreenReaderOnly: () => <>, - }; -}); -jest.mock('suricata-sid-db', () => { - return { - db: [], - }; -}); -jest.mock( - '../../../../detections/components/alerts_table/timeline_actions/use_add_to_case_actions', - () => { - return { - useAddToCaseActions: () => { - return { - addToCaseActionItems: [], - }; - }, - }; - } -); - -jest.mock('@hello-pangea/dnd', () => ({ - Droppable: ({ - children, - }: { - children: (a: DroppableProvided, b: DroppableStateSnapshot) => void; - }) => - children( - { - droppableProps: { - 'data-rfd-droppable-context-id': '123', - 'data-rfd-droppable-id': '123', - }, - innerRef: jest.fn(), - placeholder: null, - }, - { - isDraggingOver: false, - draggingOverWith: null, - draggingFromThisWith: null, - isUsingPlaceholder: false, - } - ), - Draggable: ({ - children, - }: { - children: (a: DraggableProvided, b: DraggableStateSnapshot) => void; - }) => - children( - { - draggableProps: { - 'data-rfd-draggable-context-id': '123', - 'data-rfd-draggable-id': '123', - }, - innerRef: jest.fn(), - dragHandleProps: null, - }, - { - isDragging: false, - isDropAnimating: false, - isClone: false, - dropAnimation: null, - draggingOver: null, - combineWith: null, - combineTargetFor: null, - mode: null, - } - ), - DragDropContext: ({ children }: { children: React.ReactNode }) => children, -})); - -describe('Body', () => { - const getWrapper = async ( - childrenComponent: JSX.Element, - store?: { store: ReturnType } - ) => { - const wrapper = mount(childrenComponent, { - wrappingComponent: TestProviders as EnzymeComponentType<{}>, - wrappingComponentProps: store ?? {}, - }); - await waitFor(() => wrapper.find('[data-test-subj="suricataRefs"]').exists()); - - return wrapper; - }; - const mockRefetch = jest.fn(); - let appToastsMock: jest.Mocked>; - - beforeEach(() => { - jest.mocked(useExpandableFlyoutApi).mockReturnValue({ - ...createExpandableFlyoutApiMock(), - openFlyout: mockOpenFlyout, - }); - - mockUseCurrentUser.mockReturnValue({ username: 'test-username' }); - mockUseKibana.mockReturnValue({ - services: { - application: { - navigateToApp: jest.fn(), - getUrlForApp: jest.fn(), - capabilities: { - siem: { crud_alerts: true, read_alerts: true }, - }, - }, - cases: mockCasesContract.mockCasesContract(), - data: { - search: jest.fn(), - query: jest.fn(), - dataViews: jest.fn(), - }, - uiSettings: { - get: jest.fn(), - }, - savedObjects: { - client: {}, - }, - telemetry: mockedTelemetry, - timelines: { - getLastUpdated: jest.fn(), - getLoadingPanel: jest.fn(), - getFieldBrowser: jest.fn(), - getUseAddToTimeline: () => useAddToTimeline, - }, - }, - useNavigateTo: jest.fn().mockReturnValue({ - navigateTo: jest.fn(), - }), - }); - appToastsMock = useAppToastsMock.create(); - (useAppToasts as jest.Mock).mockReturnValue(appToastsMock); - }); - - const ACTION_BUTTON_COUNT = 4; - - const props: Props = { - activePage: 0, - browserFields: mockBrowserFields, - data: [mockTimelineData[0]], - id: TimelineId.test, - refetch: mockRefetch, - renderCellValue: DefaultCellRenderer, - rowRenderers: defaultRowRenderers, - sort: mockSort, - tabType: TimelineTabs.query, - totalPages: 1, - leadingControlColumns: getDefaultControlColumn(ACTION_BUTTON_COUNT), - trailingControlColumns: [], - }; - - describe('rendering', () => { - beforeEach(() => { - mockDispatch.mockClear(); - }); - - test('it renders the column headers', async () => { - const wrapper = await getWrapper(); - expect(wrapper.find('[data-test-subj="column-headers"]').first().exists()).toEqual(true); - }); - - test('it renders the scroll container', async () => { - const wrapper = await getWrapper(); - expect(wrapper.find('[data-test-subj="timeline-body"]').first().exists()).toEqual(true); - }); - - test('it renders events', async () => { - const wrapper = await getWrapper(); - expect(wrapper.find('[data-test-subj="events"]').first().exists()).toEqual(true); - }); - test('it renders a tooltip for timestamp', async () => { - const headersJustTimestamp = defaultHeaders.filter((h) => h.id === '@timestamp'); - const state: State = { - ...mockGlobalState, - timeline: { - ...mockGlobalState.timeline, - timelineById: { - ...mockGlobalState.timeline.timelineById, - [TimelineId.test]: { - ...mockGlobalState.timeline.timelineById[TimelineId.test], - id: TimelineId.test, - columns: headersJustTimestamp, - }, - }, - }, - }; - - const store = createMockStore(state); - const wrapper = await getWrapper(, { store }); - - headersJustTimestamp.forEach(() => { - expect( - wrapper - .find('[data-test-subj="data-driven-columns"]') - .first() - .find('[data-test-subj="localized-date-tool-tip"]') - .exists() - ).toEqual(true); - }); - }); - }); - - describe('event details', () => { - beforeEach(() => { - mockDispatch.mockReset(); - }); - - test('open the expandable flyout to show event details for query tab', async () => { - const wrapper = await getWrapper(); - - wrapper.find(`[data-test-subj="expand-event"]`).first().simulate('click'); - wrapper.update(); - expect(mockDispatch).not.toHaveBeenCalled(); - expect(mockOpenFlyout).toHaveBeenCalledWith({ - right: { - id: DocumentDetailsRightPanelKey, - params: { - id: '1', - indexName: undefined, - scopeId: 'timeline-test', - }, - }, - }); - }); - - test('open the expandable flyout to show event details for pinned tab', async () => { - const wrapper = await getWrapper(); - - wrapper.find(`[data-test-subj="expand-event"]`).first().simulate('click'); - wrapper.update(); - expect(mockDispatch).not.toHaveBeenCalled(); - expect(mockOpenFlyout).toHaveBeenCalledWith({ - right: { - id: DocumentDetailsRightPanelKey, - params: { - id: '1', - indexName: undefined, - scopeId: 'timeline-test', - }, - }, - }); - }); - - test('open the expandable flyout to show event details for notes tab', async () => { - const wrapper = await getWrapper(); - - wrapper.find(`[data-test-subj="expand-event"]`).first().simulate('click'); - wrapper.update(); - expect(mockDispatch).not.toHaveBeenCalled(); - expect(mockOpenFlyout).toHaveBeenCalledWith({ - right: { - id: DocumentDetailsRightPanelKey, - params: { - id: '1', - indexName: undefined, - scopeId: 'timeline-test', - }, - }, - }); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx deleted file mode 100644 index ab60e061fcdf..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.tsx +++ /dev/null @@ -1,271 +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 { noop } from 'lodash/fp'; -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; - -import { - FIRST_ARIA_INDEX, - ARIA_COLINDEX_ATTRIBUTE, - ARIA_ROWINDEX_ATTRIBUTE, - onKeyDownFocusHandler, -} from '@kbn/timelines-plugin/public'; -import { getActionsColumnWidth } from '../../../../common/components/header_actions'; -import type { ControlColumnProps } from '../../../../../common/types'; -import type { CellValueElementProps } from '../cell_rendering'; -import { DEFAULT_COLUMN_MIN_WIDTH } from './constants'; -import type { RowRenderer, TimelineTabs } from '../../../../../common/types/timeline'; -import { RowRendererCount } from '../../../../../common/api/timeline'; -import type { BrowserFields } from '../../../../common/containers/source'; -import type { TimelineItem } from '../../../../../common/search_strategy/timeline'; -import type { inputsModel, State } from '../../../../common/store'; -import { timelineActions } from '../../../store'; -import type { OnRowSelected, OnSelectAll } from '../events'; -import { getColumnHeaders } from './column_headers/helpers'; -import { getEventIdToDataMapping } from './helpers'; -import type { Sort } from './sort'; -import { plainRowRenderer } from './renderers/plain_row_renderer'; -import { EventsTable, TimelineBody, TimelineBodyGlobalStyle } from '../styles'; -import { ColumnHeaders } from './column_headers'; -import { Events } from './events'; -import { useLicense } from '../../../../common/hooks/use_license'; -import { selectTimelineById } from '../../../store/selectors'; - -export interface Props { - activePage: number; - browserFields: BrowserFields; - data: TimelineItem[]; - id: string; - isEventViewer?: boolean; - sort: Sort[]; - refetch: inputsModel.Refetch; - renderCellValue: (props: CellValueElementProps) => React.ReactNode; - rowRenderers: RowRenderer[]; - leadingControlColumns: ControlColumnProps[]; - trailingControlColumns: ControlColumnProps[]; - tabType: TimelineTabs; - totalPages: number; - onRuleChange?: () => void; - onToggleShowNotes?: (eventId?: string) => void; -} - -/** - * The Body component is used everywhere timeline is used within the security application. It is the highest level component - * that is shared across all implementations of the timeline. - */ -export const StatefulBody = React.memo( - ({ - activePage, - browserFields, - data, - id, - isEventViewer = false, - onRuleChange, - refetch, - renderCellValue, - rowRenderers, - sort, - tabType, - totalPages, - leadingControlColumns = [], - trailingControlColumns = [], - onToggleShowNotes, - }) => { - const dispatch = useDispatch(); - const containerRef = useRef(null); - const { - columns, - eventIdToNoteIds, - excludedRowRendererIds, - isSelectAllChecked, - loadingEventIds, - pinnedEventIds, - selectedEventIds, - show, - queryFields, - selectAll, - } = useSelector((state: State) => selectTimelineById(state, id)); - - const columnHeaders = useMemo( - () => getColumnHeaders(columns, browserFields), - [browserFields, columns] - ); - - const isEnterprisePlus = useLicense().isEnterprise(); - const ACTION_BUTTON_COUNT = isEnterprisePlus ? 6 : 5; - - const onRowSelected: OnRowSelected = useCallback( - ({ eventIds, isSelected }: { eventIds: string[]; isSelected: boolean }) => { - dispatch( - timelineActions.setSelected({ - id, - eventIds: getEventIdToDataMapping(data, eventIds, queryFields), - isSelected, - isSelectAllChecked: - isSelected && Object.keys(selectedEventIds).length + 1 === data.length, - }) - ); - }, - [data, dispatch, id, queryFields, selectedEventIds] - ); - - const onSelectAll: OnSelectAll = useCallback( - ({ isSelected }: { isSelected: boolean }) => - isSelected - ? dispatch( - timelineActions.setSelected({ - id, - eventIds: getEventIdToDataMapping( - data, - data.map((event) => event._id), - queryFields - ), - isSelected, - isSelectAllChecked: isSelected, - }) - ) - : dispatch(timelineActions.clearSelected({ id })), - [data, dispatch, id, queryFields] - ); - - // Sync to selectAll so parent components can select all events - useEffect(() => { - if (selectAll && !isSelectAllChecked) { - onSelectAll({ isSelected: true }); - } - }, [isSelectAllChecked, onSelectAll, selectAll]); - - const enabledRowRenderers = useMemo(() => { - if (excludedRowRendererIds && excludedRowRendererIds.length === RowRendererCount) - return [plainRowRenderer]; - - if (!excludedRowRendererIds) return rowRenderers; - - return rowRenderers.filter((rowRenderer) => !excludedRowRendererIds.includes(rowRenderer.id)); - }, [excludedRowRendererIds, rowRenderers]); - - const actionsColumnWidth = useMemo( - () => getActionsColumnWidth(ACTION_BUTTON_COUNT), - [ACTION_BUTTON_COUNT] - ); - - const columnWidths = useMemo( - () => - columnHeaders.reduce( - (totalWidth, header) => totalWidth + (header.initialWidth ?? DEFAULT_COLUMN_MIN_WIDTH), - 0 - ), - [columnHeaders] - ); - - const leadingActionColumnsWidth = useMemo(() => { - return leadingControlColumns - ? leadingControlColumns.reduce( - (totalWidth, header) => - header.width ? totalWidth + header.width : totalWidth + actionsColumnWidth, - 0 - ) - : 0; - }, [actionsColumnWidth, leadingControlColumns]); - - const trailingActionColumnsWidth = useMemo(() => { - return trailingControlColumns - ? trailingControlColumns.reduce( - (totalWidth, header) => - header.width ? totalWidth + header.width : totalWidth + actionsColumnWidth, - 0 - ) - : 0; - }, [actionsColumnWidth, trailingControlColumns]); - - const totalWidth = useMemo(() => { - return columnWidths + leadingActionColumnsWidth + trailingActionColumnsWidth; - }, [columnWidths, leadingActionColumnsWidth, trailingActionColumnsWidth]); - - const [lastFocusedAriaColindex] = useState(FIRST_ARIA_INDEX); - - const columnCount = useMemo(() => { - return columnHeaders.length + trailingControlColumns.length + leadingControlColumns.length; - }, [columnHeaders, trailingControlColumns, leadingControlColumns]); - - const onKeyDown = useCallback( - (e: React.KeyboardEvent) => { - onKeyDownFocusHandler({ - colindexAttribute: ARIA_COLINDEX_ATTRIBUTE, - containerElement: containerRef.current, - event: e, - maxAriaColindex: columnHeaders.length + 1, - maxAriaRowindex: data.length + 1, - onColumnFocused: noop, - rowindexAttribute: ARIA_ROWINDEX_ATTRIBUTE, - }); - }, - [columnHeaders.length, containerRef, data.length] - ); - - return ( - <> - - - - - - - - - - ); - } -); - -StatefulBody.displayName = 'StatefulBody'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/mini_map/date_ranges.test.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/mini_map/date_ranges.test.ts deleted file mode 100644 index 36749de01333..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/mini_map/date_ranges.test.ts +++ /dev/null @@ -1,147 +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 moment from 'moment'; - -import type { MomentUnit } from './date_ranges'; -import { getDateRange, getDates } from './date_ranges'; - -describe('dateRanges', () => { - describe('#getDates', () => { - test('given a unit of "year", it returns the four quarters of the year', () => { - const unit: MomentUnit = 'year'; - const end = moment.utc('Mon, 31 Dec 2018 23:59:59 -0700'); - const current = moment.utc('Mon, 01 Jan 2018 00:00:00 -0700'); - - expect(getDates({ unit, end, current })).toEqual( - [ - '2018-01-01T07:00:00.000Z', - '2018-04-01T07:00:00.000Z', - '2018-07-01T07:00:00.000Z', - '2018-10-01T07:00:00.000Z', - ].map((d) => new Date(d)) - ); - }); - - test('given a unit of "month", it returns all the weeks of the month', () => { - const unit: MomentUnit = 'month'; - const end = moment.utc('Wed, 31 Oct 2018 23:59:59 -0600'); - const current = moment.utc('Mon, 01 Oct 2018 00:00:00 -0600'); - - expect(getDates({ unit, end, current })).toEqual( - [ - '2018-10-01T06:00:00.000Z', - '2018-10-08T06:00:00.000Z', - '2018-10-15T06:00:00.000Z', - '2018-10-22T06:00:00.000Z', - '2018-10-29T06:00:00.000Z', - ].map((d) => new Date(d)) - ); - }); - - test('given a unit of "week", it returns all the days of the week', () => { - const unit: MomentUnit = 'week'; - const end = moment.utc('Sat, 27 Oct 2018 23:59:59 -0600'); - const current = moment.utc('Sun, 21 Oct 2018 00:00:00 -0600'); - - expect(getDates({ unit, end, current })).toEqual( - [ - '2018-10-21T06:00:00.000Z', - '2018-10-22T06:00:00.000Z', - '2018-10-23T06:00:00.000Z', - '2018-10-24T06:00:00.000Z', - '2018-10-25T06:00:00.000Z', - '2018-10-26T06:00:00.000Z', - '2018-10-27T06:00:00.000Z', - ].map((d) => new Date(d)) - ); - }); - - test('given a unit of "day", it returns all the hours of the day', () => { - const unit: MomentUnit = 'day'; - const end = moment.utc('Tue, 23 Oct 2018 23:59:59 -0600'); - const current = moment.utc('Tue, 23 Oct 2018 00:00:00 -0600'); - - expect(getDates({ unit, end, current })).toEqual( - [ - '2018-10-23T06:00:00.000Z', - '2018-10-23T07:00:00.000Z', - '2018-10-23T08:00:00.000Z', - '2018-10-23T09:00:00.000Z', - '2018-10-23T10:00:00.000Z', - '2018-10-23T11:00:00.000Z', - '2018-10-23T12:00:00.000Z', - '2018-10-23T13:00:00.000Z', - '2018-10-23T14:00:00.000Z', - '2018-10-23T15:00:00.000Z', - '2018-10-23T16:00:00.000Z', - '2018-10-23T17:00:00.000Z', - '2018-10-23T18:00:00.000Z', - '2018-10-23T19:00:00.000Z', - '2018-10-23T20:00:00.000Z', - '2018-10-23T21:00:00.000Z', - '2018-10-23T22:00:00.000Z', - '2018-10-23T23:00:00.000Z', - '2018-10-24T00:00:00.000Z', - '2018-10-24T01:00:00.000Z', - '2018-10-24T02:00:00.000Z', - '2018-10-24T03:00:00.000Z', - '2018-10-24T04:00:00.000Z', - '2018-10-24T05:00:00.000Z', - ].map((d) => new Date(d)) - ); - }); - }); - - describe('#getDateRange', () => { - let dateSpy: jest.SpyInstance; - - beforeEach(() => { - dateSpy = jest - .spyOn(Date, 'now') - .mockImplementation(() => new Date(Date.UTC(2018, 10, 23)).valueOf()); - }); - - afterEach(() => { - dateSpy.mockReset(); - }); - - test('given a unit of "day", it returns all the hours of the day', () => { - const unit: MomentUnit = 'day'; - - const dates = getDateRange(unit); - expect(dates).toEqual( - [ - '2018-11-23T00:00:00.000Z', - '2018-11-23T01:00:00.000Z', - '2018-11-23T02:00:00.000Z', - '2018-11-23T03:00:00.000Z', - '2018-11-23T04:00:00.000Z', - '2018-11-23T05:00:00.000Z', - '2018-11-23T06:00:00.000Z', - '2018-11-23T07:00:00.000Z', - '2018-11-23T08:00:00.000Z', - '2018-11-23T09:00:00.000Z', - '2018-11-23T10:00:00.000Z', - '2018-11-23T11:00:00.000Z', - '2018-11-23T12:00:00.000Z', - '2018-11-23T13:00:00.000Z', - '2018-11-23T14:00:00.000Z', - '2018-11-23T15:00:00.000Z', - '2018-11-23T16:00:00.000Z', - '2018-11-23T17:00:00.000Z', - '2018-11-23T18:00:00.000Z', - '2018-11-23T19:00:00.000Z', - '2018-11-23T20:00:00.000Z', - '2018-11-23T21:00:00.000Z', - '2018-11-23T22:00:00.000Z', - '2018-11-23T23:00:00.000Z', - ].map((d) => new Date(d)) - ); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/mini_map/date_ranges.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/mini_map/date_ranges.ts deleted file mode 100644 index c715b2004c69..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/mini_map/date_ranges.ts +++ /dev/null @@ -1,76 +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 moment from 'moment'; - -export type MomentUnit = 'year' | 'month' | 'week' | 'day'; - -export type MomentIncrement = 'quarters' | 'months' | 'weeks' | 'days' | 'hours'; - -export type MomentUnitToIncrement = { [key in MomentUnit]: MomentIncrement }; - -const unitsToIncrements: MomentUnitToIncrement = { - day: 'hours', - month: 'weeks', - week: 'days', - year: 'quarters', -}; - -interface GetDatesParams { - unit: MomentUnit; - end: moment.Moment; - current: moment.Moment; -} - -/** - * A pure function that given a unit (e.g. `'year' | 'month' | 'week'...`) and - * a date range, returns a range of `Date`s with a granularity appropriate - * to the unit. - * - * @example - * test('given a unit of "year", it returns the four quarters of the year', () => { - * const unit: MomentUnit = 'year'; - * const end = moment.utc('Mon, 31 Dec 2018 23:59:59 -0700'); - * const current = moment.utc('Mon, 01 Jan 2018 00:00:00 -0700'); - * - * expect(getDates({ unit, end, current })).toEqual( - * [ - * '2018-01-01T07:00:00.000Z', - * '2018-04-01T06:00:00.000Z', - * '2018-07-01T06:00:00.000Z', - * '2018-10-01T06:00:00.000Z' - * ].map(d => new Date(d)) - * ); - * }); - */ -export const getDates = ({ unit, end, current }: GetDatesParams): Date[] => - current <= end - ? [ - current.toDate(), - ...getDates({ - current: current.clone().add(1, unitsToIncrements[unit]), - end, - unit, - }), - ] - : []; - -/** - * An impure function (it performs IO to get the current `Date`) that, - * given a unit (e.g. `'year' | 'month' | 'week'...`), it - * returns range of `Date`s with a granularity appropriate to the unit. - */ -export function getDateRange(unit: MomentUnit): Date[] { - const current = moment().utc().startOf(unit); - const end = moment().utc().endOf(unit); - - return getDates({ - current, - end, // TODO: this should be relative to `unit` - unit, - }); -} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field_udt.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field_udt.test.tsx index d731b6e831f9..c1fe2f3278dd 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field_udt.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field_udt.test.tsx @@ -6,7 +6,7 @@ */ import { mockTimelineData } from '../../../../../common/mock'; -import { defaultUdtHeaders } from '../../unified_components/default_headers'; +import { defaultUdtHeaders } from '../column_headers/default_headers'; import { getFormattedFields } from './formatted_field_udt'; import type { DataTableRecord } from '@kbn/discover-utils/types'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_column_renderer.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_column_renderer.test.tsx index 551ba3c4ac57..ad75ef79aa04 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_column_renderer.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/get_column_renderer.test.tsx @@ -13,13 +13,13 @@ import type { TimelineNonEcsData } from '../../../../../../common/search_strateg import { mockTimelineData } from '../../../../../common/mock'; import { TestProviders } from '../../../../../common/mock/test_providers'; import { getEmptyValue } from '../../../../../common/components/empty_value'; -import { defaultHeaders } from '../column_headers/default_headers'; import { columnRenderers } from '.'; import { getColumnRenderer } from './get_column_renderer'; import { getValues, findItem, deleteItemIdx } from './helpers'; import { useMountAppended } from '../../../../../common/utils/use_mount_appended'; import { TimelineId } from '../../../../../../common/types/timeline'; +import { defaultUdtHeaders } from '../column_headers/default_headers'; jest.mock('../../../../../common/lib/kibana'); @@ -47,7 +47,7 @@ describe('get_column_renderer', () => { columnName, eventId: _id, values: getValues(columnName, nonSuricata), - field: defaultHeaders[1], + field: defaultUdtHeaders[1], scopeId: TimelineId.test, }); @@ -62,7 +62,7 @@ describe('get_column_renderer', () => { columnName, eventId: _id, values: getValues(columnName, nonSuricata), - field: defaultHeaders[1], + field: defaultUdtHeaders[1], scopeId: TimelineId.test, }); const wrapper = mount( @@ -82,7 +82,7 @@ describe('get_column_renderer', () => { columnName, eventId: _id, values: getValues(columnName, nonSuricata), - field: defaultHeaders[7], + field: defaultUdtHeaders[7], scopeId: TimelineId.test, }); const wrapper = mount( @@ -100,7 +100,7 @@ describe('get_column_renderer', () => { columnName, eventId: _id, values: getValues(columnName, nonSuricata), - field: defaultHeaders[7], + field: defaultUdtHeaders[7], scopeId: TimelineId.test, }); const wrapper = mount( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/reason_column_renderer.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/reason_column_renderer.test.tsx index a5cd33efdd5c..3912d7d9ef8c 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/reason_column_renderer.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/reason_column_renderer.test.tsx @@ -8,7 +8,6 @@ import React from 'react'; import { mockTimelineData, TestProviders } from '../../../../../common/mock'; -import { defaultColumnHeaderType } from '../column_headers/default_headers'; import { REASON_FIELD_NAME } from './constants'; import { reasonColumnRenderer } from './reason_column_renderer'; import { plainColumnRenderer } from './plain_column_renderer'; @@ -19,6 +18,7 @@ import { RowRendererIdEnum } from '../../../../../../common/api/timeline'; import { render } from '@testing-library/react'; import { cloneDeep } from 'lodash'; import { TableId } from '@kbn/securitysolution-data-table'; +import { defaultColumnHeaderType } from '../column_headers/default_headers'; jest.mock('./plain_column_renderer'); jest.mock('../../../../../common/components/link_to', () => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/__snapshots__/sort_indicator.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/__snapshots__/sort_indicator.test.tsx.snap deleted file mode 100644 index 8a7b179da059..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/__snapshots__/sort_indicator.test.tsx.snap +++ /dev/null @@ -1,19 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SortIndicator rendering renders correctly against snapshot 1`] = ` - - - - -`; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/sort_indicator.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/sort_indicator.test.tsx deleted file mode 100644 index 56f98a6795cd..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/sort_indicator.test.tsx +++ /dev/null @@ -1,85 +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 { mount, shallow } from 'enzyme'; -import React from 'react'; -import { Direction } from '../../../../../../common/search_strategy'; - -import * as i18n from '../translations'; - -import { getDirection, SortIndicator } from './sort_indicator'; - -describe('SortIndicator', () => { - describe('rendering', () => { - test('renders correctly against snapshot', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); - }); - - test('it renders the expected sort indicator when direction is ascending', () => { - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="sortIndicator"]').first().prop('type')).toEqual( - 'sortUp' - ); - }); - - test('it renders the expected sort indicator when direction is descending', () => { - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="sortIndicator"]').first().prop('type')).toEqual( - 'sortDown' - ); - }); - - test('it renders the expected sort indicator when direction is `none`', () => { - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="sortIndicator"]').first().prop('type')).toEqual( - 'empty' - ); - }); - }); - - describe('getDirection', () => { - test('it returns the expected symbol when the direction is ascending', () => { - expect(getDirection(Direction.asc)).toEqual('sortUp'); - }); - - test('it returns the expected symbol when the direction is descending', () => { - expect(getDirection(Direction.desc)).toEqual('sortDown'); - }); - - test('it returns the expected symbol (undefined) when the direction is neither ascending, nor descending', () => { - expect(getDirection('none')).toEqual(undefined); - }); - }); - - describe('sort indicator tooltip', () => { - test('it returns the expected tooltip when the direction is ascending', () => { - const wrapper = mount(); - - expect( - wrapper.find('[data-test-subj="sort-indicator-tooltip"]').first().props().content - ).toEqual(i18n.SORTED_ASCENDING); - }); - - test('it returns the expected tooltip when the direction is descending', () => { - const wrapper = mount(); - - expect( - wrapper.find('[data-test-subj="sort-indicator-tooltip"]').first().props().content - ).toEqual(i18n.SORTED_DESCENDING); - }); - - test('it does NOT render a tooltip when sort direction is `none`', () => { - const wrapper = mount(); - - expect(wrapper.find('[data-test-subj="sort-indicator-tooltip"]').exists()).toBe(false); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/sort_indicator.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/sort_indicator.tsx deleted file mode 100644 index 82c25f00c78a..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/sort_indicator.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 { EuiIcon, EuiToolTip } from '@elastic/eui'; -import React from 'react'; - -import * as i18n from '../translations'; -import { SortNumber } from './sort_number'; - -import { Direction } from '../../../../../../common/search_strategy'; -import type { SortDirection } from '../../../../../../common/types/timeline'; - -enum SortDirectionIndicatorEnum { - SORT_UP = 'sortUp', - SORT_DOWN = 'sortDown', -} - -export type SortDirectionIndicator = undefined | SortDirectionIndicatorEnum; - -/** Returns the symbol that corresponds to the specified `SortDirection` */ -export const getDirection = (sortDirection: SortDirection): SortDirectionIndicator => { - switch (sortDirection) { - case Direction.asc: - return SortDirectionIndicatorEnum.SORT_UP; - case Direction.desc: - return SortDirectionIndicatorEnum.SORT_DOWN; - case 'none': - return undefined; - default: - throw new Error('Unhandled sort direction'); - } -}; - -interface Props { - sortDirection: SortDirection; - sortNumber: number; -} - -/** Renders a sort indicator */ -export const SortIndicator = React.memo(({ sortDirection, sortNumber }) => { - const direction = getDirection(sortDirection); - - if (direction != null) { - return ( - - <> - - - - - ); - } else { - return ; - } -}); - -SortIndicator.displayName = 'SortIndicator'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/sort_number.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/sort_number.tsx deleted file mode 100644 index 3fdd31eae5c4..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/sort/sort_number.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 { EuiIcon, EuiNotificationBadge } from '@elastic/eui'; -import React from 'react'; - -interface Props { - sortNumber: number; -} - -export const SortNumber = React.memo(({ sortNumber }) => { - if (sortNumber >= 0) { - return ( - - {sortNumber + 1} - - ); - } else { - return ; - } -}); - -SortNumber.displayName = 'SortNumber'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.test.tsx index 031604c6a3da..41cdec6d6d4b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.test.tsx @@ -9,7 +9,7 @@ import { TimelineTabs } from '../../../../../common/types'; import { DataLoadingState } from '@kbn/unified-data-table'; import React from 'react'; import { UnifiedTimeline } from '../unified_components'; -import { defaultUdtHeaders } from '../unified_components/default_headers'; +import { defaultUdtHeaders } from './column_headers/default_headers'; import type { UnifiedTimelineBodyProps } from './unified_timeline_body'; import { UnifiedTimelineBody } from './unified_timeline_body'; import { render, screen } from '@testing-library/react'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.tsx index fe6b668ed683..95feab854361 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.tsx @@ -10,7 +10,7 @@ import React, { useEffect, useState, useMemo } from 'react'; import { RootDragDropProvider } from '@kbn/dom-drag-drop'; import { StyledTableFlexGroup, StyledUnifiedTableFlexItem } from '../unified_components/styles'; import { UnifiedTimeline } from '../unified_components'; -import { defaultUdtHeaders } from '../unified_components/default_headers'; +import { defaultUdtHeaders } from './column_headers/default_headers'; import type { PaginationInputPaginated, TimelineItem } from '../../../../../common/search_strategy'; export interface UnifiedTimelineBodyProps extends ComponentProps { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx index 9e5006267d32..ec230139dc95 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/cell_rendering/default_cell_renderer.tsx @@ -8,7 +8,7 @@ import React, { useMemo } from 'react'; import styled from 'styled-components'; -import { useGetMappedNonEcsValue } from '../body/data_driven_columns'; +import { useGetMappedNonEcsValue } from '../../../../common/utils/get_mapped_non_ecs_value'; import { columnRenderers } from '../body/renderers'; import { getColumnRenderer } from '../body/renderers/get_column_renderer'; import type { CellValueElementProps } from '.'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.test.tsx index f7dad276cb93..9f187f91dcdf 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.test.tsx @@ -17,6 +17,7 @@ import { buildIsOneOfQueryMatch, buildIsQueryMatch, handleIsOperator, + isFullScreen, isPrimitiveArray, showGlobalFilters, } from './helpers'; @@ -392,3 +393,42 @@ describe('isStringOrNumberArray', () => { }); }); }); + +describe('isFullScreen', () => { + describe('globalFullScreen is false', () => { + it('should return false if isActiveTimelines is false', () => { + const result = isFullScreen({ + globalFullScreen: false, + isActiveTimelines: false, + timelineFullScreen: true, + }); + expect(result).toBe(false); + }); + it('should return false if timelineFullScreen is false', () => { + const result = isFullScreen({ + globalFullScreen: false, + isActiveTimelines: true, + timelineFullScreen: false, + }); + expect(result).toBe(false); + }); + }); + describe('globalFullScreen is true', () => { + it('should return true if isActiveTimelines is true and timelineFullScreen is true', () => { + const result = isFullScreen({ + globalFullScreen: true, + isActiveTimelines: true, + timelineFullScreen: true, + }); + expect(result).toBe(true); + }); + it('should return true if isActiveTimelines is false', () => { + const result = isFullScreen({ + globalFullScreen: true, + isActiveTimelines: false, + timelineFullScreen: false, + }); + expect(result).toBe(true); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx index 04f08f203ec7..43c4648abb83 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/helpers.tsx @@ -282,3 +282,14 @@ export const TIMELINE_FILTER_DROP_AREA = 'timeline-filter-drop-area'; export const getNonDropAreaFilters = (filters: Filter[] = []) => filters.filter((f: Filter) => f.meta.controlledBy !== TIMELINE_FILTER_DROP_AREA); + +export const isFullScreen = ({ + globalFullScreen, + isActiveTimelines, + timelineFullScreen, +}: { + globalFullScreen: boolean; + isActiveTimelines: boolean; + timelineFullScreen: boolean; +}) => + (isActiveTimelines && timelineFullScreen) || (isActiveTimelines === false && globalFullScreen); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx index ea0edabdfe7b..05d15f076f56 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.tsx @@ -29,7 +29,7 @@ import { useTimelineFullScreen } from '../../../common/containers/use_full_scree import { EXIT_FULL_SCREEN_CLASS_NAME } from '../../../common/components/exit_full_screen'; import { useResolveConflict } from '../../../common/hooks/use_resolve_conflict'; import { sourcererSelectors } from '../../../common/store'; -import { defaultUdtHeaders } from './unified_components/default_headers'; +import { defaultUdtHeaders } from './body/column_headers/default_headers'; const TimelineTemplateBadge = styled.div` background: ${({ theme }) => theme.eui.euiColorVis3_behindText}; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/styles.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/styles.tsx index 97762de6bcb9..1591c7f8c791 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/styles.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/styles.tsx @@ -10,11 +10,6 @@ import { rgba } from 'polished'; import styled, { createGlobalStyle } from 'styled-components'; import { IS_TIMELINE_FIELD_DRAGGING_CLASS_NAME } from '@kbn/securitysolution-t-grid'; -import type { TimelineEventsType } from '../../../../common/types/timeline'; - -import { ACTIONS_COLUMN_ARIA_COL_INDEX } from './helpers'; -import { EVENTS_TABLE_ARIA_LABEL } from './translations'; - /** * TIMELINE BODY */ @@ -73,79 +68,6 @@ TimelineBody.displayName = 'TimelineBody'; export const EVENTS_TABLE_CLASS_NAME = 'siemEventsTable'; -interface EventsTableProps { - $activePage: number; - $columnCount: number; - columnWidths: number; - $rowCount: number; - $totalPages: number; -} - -export const EventsTable = styled.div.attrs( - ({ className = '', $columnCount, columnWidths, $activePage, $rowCount, $totalPages }) => ({ - 'aria-label': EVENTS_TABLE_ARIA_LABEL({ activePage: $activePage + 1, totalPages: $totalPages }), - 'aria-colcount': `${$columnCount}`, - 'aria-rowcount': `${$rowCount + 1}`, - className: `siemEventsTable ${className}`, - role: 'grid', - style: { - minWidth: `${columnWidths}px`, - }, - tabindex: '-1', - }) -)` - padding: 3px; -`; - -/* EVENTS HEAD */ - -export const EventsThead = styled.div.attrs(({ className = '' }) => ({ - className: `siemEventsTable__thead ${className}`, - role: 'rowgroup', -}))` - background-color: ${({ theme }) => theme.eui.euiColorEmptyShade}; - border-bottom: ${({ theme }) => theme.eui.euiBorderWidthThick} solid - ${({ theme }) => theme.eui.euiColorLightShade}; - position: sticky; - top: 0; - z-index: ${({ theme }) => theme.eui.euiZLevel1}; -`; - -export const EventsTrHeader = styled.div.attrs(({ className }) => ({ - 'aria-rowindex': '1', - className: `siemEventsTable__trHeader ${className}`, - role: 'row', -}))` - display: flex; -`; - -export const EventsThGroupActions = styled.div.attrs(({ className = '' }) => ({ - 'aria-colindex': `${ACTIONS_COLUMN_ARIA_COL_INDEX}`, - className: `siemEventsTable__thGroupActions ${className}`, - role: 'columnheader', - tabIndex: '0', -}))<{ actionsColumnWidth: number; isEventViewer: boolean }>` - display: flex; - flex: 0 0 - ${({ actionsColumnWidth, isEventViewer }) => - `${!isEventViewer ? actionsColumnWidth + 4 : actionsColumnWidth}px`}; - min-width: 0; - padding-left: ${({ isEventViewer }) => - !isEventViewer ? '4px;' : '0;'}; // match timeline event border -`; - -export const EventsThGroupData = styled.div.attrs(({ className = '' }) => ({ - className: `siemEventsTable__thGroupData ${className}`, -}))<{ isDragging?: boolean }>` - display: flex; - - > div:hover .siemEventsHeading__handle { - display: ${({ isDragging }) => (isDragging ? 'none' : 'block')}; - opacity: 1; - visibility: visible; - } -`; - export const EventsTh = styled.div.attrs<{ role: string }>( ({ className = '', role = 'columnheader' }) => ({ className: `siemEventsTable__th ${className}`, @@ -197,76 +119,6 @@ export const EventsThContent = styled.div.attrs(({ className = '' }) => ({ } `; -/* EVENTS BODY */ - -export const EventsTbody = styled.div.attrs(({ className = '' }) => ({ - className: `siemEventsTable__tbody ${className}`, - role: 'rowgroup', -}))` - overflow-x: hidden; -`; - -export const EventsTrGroup = styled.div.attrs( - ({ className = '', $ariaRowindex }: { className?: string; $ariaRowindex: number }) => ({ - 'aria-rowindex': `${$ariaRowindex}`, - className: `siemEventsTable__trGroup ${className}`, - role: 'row', - }) -)<{ - className?: string; - eventType: Omit; - isEvenEqlSequence: boolean; - isBuildingBlockType: boolean; - isExpanded: boolean; - showLeftBorder: boolean; -}>` - border-bottom: ${({ theme }) => theme.eui.euiBorderWidthThin} solid - ${({ theme }) => theme.eui.euiColorLightShade}; - ${({ theme, eventType, isEvenEqlSequence, showLeftBorder }) => - showLeftBorder - ? `border-left: 4px solid - ${ - eventType === 'raw' - ? theme.eui.euiColorLightShade - : eventType === 'eql' && isEvenEqlSequence - ? theme.eui.euiColorPrimary - : eventType === 'eql' && !isEvenEqlSequence - ? theme.eui.euiColorAccent - : theme.eui.euiColorWarning - }` - : ''}; - ${({ isBuildingBlockType }) => - isBuildingBlockType - ? 'background: repeating-linear-gradient(127deg, rgba(245, 167, 0, 0.2), rgba(245, 167, 0, 0.2) 1px, rgba(245, 167, 0, 0.05) 2px, rgba(245, 167, 0, 0.05) 10px);' - : ''}; - ${({ eventType, isEvenEqlSequence }) => - eventType === 'eql' - ? isEvenEqlSequence - ? 'background: repeating-linear-gradient(127deg, rgba(0, 107, 180, 0.2), rgba(0, 107, 180, 0.2) 1px, rgba(0, 107, 180, 0.05) 2px, rgba(0, 107, 180, 0.05) 10px);' - : 'background: repeating-linear-gradient(127deg, rgba(221, 10, 115, 0.2), rgba(221, 10, 115, 0.2) 1px, rgba(221, 10, 115, 0.05) 2px, rgba(221, 10, 115, 0.05) 10px);' - : ''}; - - &:hover { - background-color: ${({ theme }) => theme.eui.euiTableHoverColor}; - } - - ${({ isExpanded, theme }) => - isExpanded && - ` - background: ${theme.eui.euiTableSelectedColor}; - - &:hover { - ${theme.eui.euiTableHoverSelectedColor} - } - `} -`; - -export const EventsTrData = styled.div.attrs(({ className = '' }) => ({ - className: `siemEventsTable__trData ${className}`, -}))` - display: flex; -`; - const TIMELINE_EVENT_DETAILS_OFFSET = 40; interface WidthProp { @@ -295,57 +147,6 @@ export const EventsTrSupplement = styled.div.attrs(({ className = '' }) => ({ } `; -export const EventsTdGroupActions = styled.div.attrs(({ className = '' }) => ({ - 'aria-colindex': `${ACTIONS_COLUMN_ARIA_COL_INDEX}`, - className: `siemEventsTable__tdGroupActions ${className}`, - role: 'gridcell', -}))<{ width: number }>` - align-items: center; - display: flex; - flex: 0 0 ${({ width }) => `${width}px`}; - min-width: 0; -`; - -export const EventsTdGroupData = styled.div.attrs(({ className = '' }) => ({ - className: `siemEventsTable__tdGroupData ${className}`, -}))` - display: flex; -`; -interface EventsTdProps { - $ariaColumnIndex?: number; - width?: number; -} - -export const EVENTS_TD_CLASS_NAME = 'siemEventsTable__td'; - -export const EventsTd = styled.div.attrs( - ({ className = '', $ariaColumnIndex, width }) => { - const common = { - className: `siemEventsTable__td ${className}`, - role: 'gridcell', - style: { - flexBasis: width ? `${width}px` : 'auto', - }, - }; - - return $ariaColumnIndex != null - ? { - ...common, - 'aria-colindex': `${$ariaColumnIndex}`, - } - : common; - } -)` - align-items: center; - display: flex; - flex-shrink: 0; - min-width: 0; - - .siemEventsTable__tdGroupActions &:first-child:last-child { - flex: 1; - } -`; - export const EventsTdContent = styled.div.attrs(({ className }) => ({ className: `siemEventsTable__tdContent ${className != null ? className : ''}`, }))<{ textAlign?: string; width?: number }>` @@ -363,89 +164,9 @@ export const EventsTdContent = styled.div.attrs(({ className }) => ({ } `; -/** - * EVENTS HEADING - */ - -export const EventsHeading = styled.div.attrs(({ className = '' }) => ({ - className: `siemEventsHeading ${className}`, -}))<{ isLoading: boolean }>` - align-items: center; - display: flex; - - &:hover { - cursor: ${({ isLoading }) => (isLoading ? 'wait' : 'grab')}; - } -`; - -export const EventsHeadingTitleButton = styled.button.attrs(({ className = '' }) => ({ - className: `siemEventsHeading__title siemEventsHeading__title--aggregatable ${className}`, - type: 'button', -}))` - align-items: center; - display: flex; - font-weight: inherit; - min-width: 0; - - &:hover, - &:focus { - color: ${({ theme }) => theme.eui.euiColorPrimary}; - text-decoration: underline; - } - - &:hover { - cursor: pointer; - } - - & > * + * { - margin-left: ${({ theme }) => theme.eui.euiSizeXS}; - } -`; - -export const EventsHeadingTitleSpan = styled.span.attrs(({ className }) => ({ - className: `siemEventsHeading__title siemEventsHeading__title--notAggregatable ${className}`, -}))` - min-width: 0; -`; - -export const EventsHeadingExtra = styled.div.attrs(({ className = '' }) => ({ - className: `siemEventsHeading__extra ${className}` as string, -}))` - margin-left: auto; - margin-right: 2px; - - &.siemEventsHeading__extra--close { - opacity: 0; - transition: all ${({ theme }) => theme.eui.euiAnimSpeedNormal} ease; - visibility: hidden; - - .siemEventsTable__th:hover & { - opacity: 1; - visibility: visible; - } - } -`; - -export const EventsHeadingHandle = styled.div.attrs(({ className = '' }) => ({ - className: `siemEventsHeading__handle ${className}`, -}))` - background-color: ${({ theme }) => theme.eui.euiBorderColor}; - height: 100%; - opacity: 0; - transition: all ${({ theme }) => theme.eui.euiAnimSpeedNormal} ease; - visibility: hidden; - width: ${({ theme }) => theme.eui.euiBorderWidthThick}; - - &:hover { - background-color: ${({ theme }) => theme.eui.euiColorPrimary}; - cursor: col-resize; - } -`; - /** * EVENTS LOADING */ - export const EventsLoading = styled(EuiLoadingSpinner)` margin: 0 2px; vertical-align: middle; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.test.tsx index 7c8949c1b612..23fb44d04910 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.test.tsx @@ -35,9 +35,6 @@ jest.mock('../../../../containers/details', () => ({ jest.mock('../../../fields_browser', () => ({ useFieldBrowserOptions: jest.fn(), })); -jest.mock('../../body/events', () => ({ - Events: () => <>, -})); jest.mock('../../../../../sourcerer/containers'); jest.mock('../../../../../sourcerer/containers/use_signal_helpers', () => ({ diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx index 602d2353f342..5c4a592d99a7 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx @@ -46,6 +46,7 @@ import { useTimelineControlColumn } from '../shared/use_timeline_control_columns import { LeftPanelNotesTab } from '../../../../../flyout/document_details/left'; import { useNotesInFlyout } from '../../properties/use_notes_in_flyout'; import { NotesFlyout } from '../../properties/notes_flyout'; +import { NotesEventTypes, DocumentEventTypes } from '../../../../../common/lib/telemetry'; import { TimelineRefetch } from '../../refetch_timeline'; export type Props = TimelineTabCommonProps & PropsFromRedux; @@ -161,10 +162,10 @@ export const EqlTabContentComponent: React.FC = ({ }, }, }); - telemetry.reportOpenNoteInExpandableFlyoutClicked({ + telemetry.reportEvent(NotesEventTypes.OpenNoteInExpandableFlyoutClicked, { location: timelineId, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: timelineId, panel: 'left', }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.test.tsx index 0df50a8cf47c..55604cd958c2 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.test.tsx @@ -14,7 +14,7 @@ import { DefaultCellRenderer } from '../../cell_rendering/default_cell_renderer' import { defaultHeaders, mockTimelineData } from '../../../../../common/mock'; import { TestProviders } from '../../../../../common/mock/test_providers'; import { defaultRowRenderers } from '../../body/renderers'; -import type { Sort } from '../../body/sort'; +import type { SortColumnTimeline as Sort } from '../../../../../../common/types/timeline'; import { TimelineId } from '../../../../../../common/types/timeline'; import { useTimelineEvents } from '../../../../containers'; import { useTimelineEventsDetails } from '../../../../containers/details'; @@ -38,9 +38,6 @@ jest.mock('../../../../containers/details', () => ({ jest.mock('../../../fields_browser', () => ({ useFieldBrowserOptions: jest.fn(), })); -jest.mock('../../body/events', () => ({ - Events: () => <>, -})); jest.mock('../../../../../sourcerer/containers'); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx index a12f3bb9fd53..0b2553d23ac5 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx @@ -21,7 +21,6 @@ import { useKibana } from '../../../../../common/lib/kibana'; import { timelineSelectors } from '../../../../store'; import type { Direction } from '../../../../../../common/search_strategy'; import { useTimelineEvents } from '../../../../containers'; -import { defaultHeaders } from '../../body/column_headers/default_headers'; import { requiredFieldsForActions } from '../../../../../detections/components/alerts_table/default_config'; import { SourcererScopeName } from '../../../../../sourcerer/store/model'; import { timelineDefaults } from '../../../../store/defaults'; @@ -37,6 +36,8 @@ import { useTimelineControlColumn } from '../shared/use_timeline_control_columns import { LeftPanelNotesTab } from '../../../../../flyout/document_details/left'; import { useNotesInFlyout } from '../../properties/use_notes_in_flyout'; import { NotesFlyout } from '../../properties/notes_flyout'; +import { NotesEventTypes, DocumentEventTypes } from '../../../../../common/lib/telemetry'; +import { defaultUdtHeaders } from '../../body/column_headers/default_headers'; interface PinnedFilter { bool: { @@ -111,7 +112,7 @@ export const PinnedTabContentComponent: React.FC = ({ }, [pinnedEventIds]); const timelineQueryFields = useMemo(() => { - const columnsHeader = isEmpty(columns) ? defaultHeaders : columns; + const columnsHeader = isEmpty(columns) ? defaultUdtHeaders : columns; const columnFields = columnsHeader.map((c) => c.id); return [...columnFields, ...requiredFieldsForActions]; @@ -190,10 +191,10 @@ export const PinnedTabContentComponent: React.FC = ({ }, }, }); - telemetry.reportOpenNoteInExpandableFlyoutClicked({ + telemetry.reportEvent(NotesEventTypes.OpenNoteInExpandableFlyoutClicked, { location: timelineId, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: timelineId, panel: 'left', }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.test.tsx index 70afec0d7313..f0a2c06bbffb 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.test.tsx @@ -30,8 +30,10 @@ import { useDispatch } from 'react-redux'; import type { ExperimentalFeatures } from '../../../../../../common'; import { allowedExperimentalValues } from '../../../../../../common'; import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; -import { defaultUdtHeaders } from '../../unified_components/default_headers'; -import { defaultColumnHeaderType } from '../../body/column_headers/default_headers'; +import { + defaultUdtHeaders, + defaultColumnHeaderType, +} from '../../body/column_headers/default_headers'; import { useUserPrivileges } from '../../../../../common/components/user_privileges'; import { getEndpointPrivilegesInitialStateMock } from '../../../../../common/components/user_privileges/endpoint/mocks'; import * as timelineActions from '../../../../store/actions'; @@ -52,10 +54,6 @@ jest.mock('../../../fields_browser', () => ({ useFieldBrowserOptions: jest.fn(), })); -jest.mock('../../body/events', () => ({ - Events: () => <>, -})); - jest.mock('../../../../../sourcerer/containers'); jest.mock('../../../../../sourcerer/containers/use_signal_helpers', () => ({ useSignalHelpers: () => ({ signalIndexNeedsInit: false }), diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx index 8ea1db39a361..ec61c67a3954 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx @@ -49,6 +49,7 @@ import { useTimelineColumns } from '../shared/use_timeline_columns'; import { useTimelineControlColumn } from '../shared/use_timeline_control_columns'; import { NotesFlyout } from '../../properties/notes_flyout'; import { useNotesInFlyout } from '../../properties/use_notes_in_flyout'; +import { DocumentEventTypes, NotesEventTypes } from '../../../../../common/lib/telemetry'; const compareQueryProps = (prevProps: Props, nextProps: Props) => prevProps.kqlMode === nextProps.kqlMode && @@ -228,10 +229,10 @@ export const QueryTabContentComponent: React.FC = ({ }, }, }); - telemetry.reportOpenNoteInExpandableFlyoutClicked({ + telemetry.reportEvent(NotesEventTypes.OpenNoteInExpandableFlyoutClicked, { location: timelineId, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: timelineId, panel: 'left', }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/session/use_session_view.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/session/use_session_view.tsx index eae2eec549df..67b9fd50eac2 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/session/use_session_view.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/session/use_session_view.tsx @@ -23,7 +23,6 @@ import { useKibana } from '../../../../../common/lib/kibana'; import * as i18n from './translations'; import { TimelineTabs } from '../../../../../../common/types/timeline'; import { SourcererScopeName } from '../../../../../sourcerer/store/model'; -import { isFullScreen } from '../../body/column_headers'; import { SCROLLING_DISABLED_CLASS_NAME } from '../../../../../../common/constants'; import { FULL_SCREEN } from '../../body/column_headers/translations'; import { EXIT_FULL_SCREEN } from '../../../../../common/components/exit_full_screen/translations'; @@ -35,6 +34,8 @@ import { useUserPrivileges } from '../../../../../common/components/user_privile import { timelineActions, timelineSelectors } from '../../../../store'; import { timelineDefaults } from '../../../../store/defaults'; import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector'; +import { DocumentEventTypes } from '../../../../../common/lib/telemetry'; +import { isFullScreen } from '../../helpers'; const FullScreenButtonIcon = styled(EuiButtonIcon)` margin: 4px 0 4px 0; @@ -287,7 +288,7 @@ export const useSessionView = ({ scopeId, height }: { scopeId: string; height?: }, }, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: scopeId, panel: 'right', }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/layout.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/layout.tsx index aacb38ea2e79..1cac4dc2536f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/layout.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/layout.tsx @@ -5,14 +5,7 @@ * 2.0. */ -import { - EuiFlexGroup, - EuiFlexItem, - EuiFlyoutHeader, - EuiFlyoutBody, - EuiFlyoutFooter, - EuiBadge, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlyoutHeader, EuiBadge } from '@elastic/eui'; import styled from 'styled-components'; export const TabHeaderContainer = styled.div` @@ -33,46 +26,12 @@ export const StyledEuiFlyoutHeader = styled(EuiFlyoutHeader)` } `; -export const StyledEuiFlyoutBody = styled(EuiFlyoutBody)` - overflow-y: hidden; - flex: 1; - - .euiFlyoutBody__overflow { - overflow: hidden; - mask-image: none; - } - - .euiFlyoutBody__overflowContent { - padding: 0; - height: 100%; - display: flex; - } -`; - -export const StyledEuiFlyoutFooter = styled(EuiFlyoutFooter)` - background: none; - &.euiFlyoutFooter { - ${({ theme }) => `padding: ${theme.eui.euiSizeS} 0;`} - } -`; - export const FullWidthFlexGroup = styled(EuiFlexGroup)` margin: 0; width: 100%; overflow: hidden; `; -export const ScrollableFlexItem = styled(EuiFlexItem)` - ${({ theme }) => `margin: 0 ${theme.eui.euiSizeM};`} - overflow: hidden; -`; - -export const SourcererFlex = styled(EuiFlexItem)` - align-items: flex-end; -`; - -SourcererFlex.displayName = 'SourcererFlex'; - export const VerticalRule = styled.div` width: 2px; height: 100%; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.test.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.test.ts index 8bbda9a255a0..926082ff9ed4 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.test.ts @@ -8,7 +8,7 @@ import { TestProviders } from '../../../../../common/mock'; import { renderHook } from '@testing-library/react-hooks'; import { useTimelineColumns } from './use_timeline_columns'; -import { defaultUdtHeaders } from '../../unified_components/default_headers'; +import { defaultUdtHeaders } from '../../body/column_headers/default_headers'; import type { ColumnHeaderOptions } from '../../../../../../common/types/timeline/columns'; jest.mock('../../../../../common/hooks/use_experimental_features', () => ({ diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.tsx index f42bf47c7642..006c6ba1eb67 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/use_timeline_columns.tsx @@ -9,7 +9,7 @@ import { useMemo } from 'react'; import { SourcererScopeName } from '../../../../../sourcerer/store/model'; import { useSourcererDataView } from '../../../../../sourcerer/containers'; import { requiredFieldsForActions } from '../../../../../detections/components/alerts_table/default_config'; -import { defaultUdtHeaders } from '../../unified_components/default_headers'; +import { defaultUdtHeaders } from '../../body/column_headers/default_headers'; import type { ColumnHeaderOptions } from '../../../../../../common/types'; import { memoizedGetTimelineColumnHeaders } from './utils'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/utils.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/utils.ts index 879e4b140a61..543c7daaf867 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/utils.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/shared/utils.ts @@ -7,7 +7,7 @@ import type { BrowserFields, ColumnHeaderOptions } from '@kbn/timelines-plugin/common'; import memoizeOne from 'memoize-one'; import type { ControlColumnProps } from '../../../../../../common/types'; -import type { Sort } from '../../body/sort'; +import type { SortColumnTimeline as Sort } from '../../../../../../common/types/timeline'; import type { TimelineItem } from '../../../../../../common/search_strategy'; import type { inputsModel } from '../../../../../common/store'; import { getColumnHeaders } from '../../body/column_headers/helpers'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.test.tsx index cfdb2b0d2dbf..cc8b24710e5a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/custom_timeline_data_grid_body.test.tsx @@ -12,7 +12,7 @@ import { CustomTimelineDataGridBody } from './custom_timeline_data_grid_body'; import { mockTimelineData, TestProviders } from '../../../../../common/mock'; import type { TimelineItem } from '@kbn/timelines-plugin/common'; import type { DataTableRecord } from '@kbn/discover-utils/types'; -import { defaultUdtHeaders } from '../default_headers'; +import { defaultUdtHeaders } from '../../body/column_headers/default_headers'; import type { EuiDataGridColumn } from '@elastic/eui'; import { useStatefulRowRenderer } from '../../body/events/stateful_row_renderer/use_stateful_row_renderer'; import { TIMELINE_EVENT_DETAIL_ROW_ID } from '../../body/constants'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.test.tsx index 78ffadeb37ff..649817d5f8ef 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.test.tsx @@ -8,7 +8,6 @@ import { createMockStore, mockTimelineData, TestProviders } from '../../../../../common/mock'; import React from 'react'; import { TimelineDataTable } from '.'; -import { defaultUdtHeaders } from '../default_headers'; import { TimelineId, TimelineTabs } from '../../../../../../common/types'; import { DataLoadingState } from '@kbn/unified-data-table'; import { fireEvent, render, screen, waitFor, within } from '@testing-library/react'; @@ -18,6 +17,7 @@ import { getColumnHeaders } from '../../body/column_headers/helpers'; import { mockSourcererScope } from '../../../../../sourcerer/containers/mocks'; import { timelineActions } from '../../../../store'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { defaultUdtHeaders } from '../../body/column_headers/default_headers'; jest.mock('../../../../../sourcerer/containers'); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx index 875c147d6a70..fa5b83f23576 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx @@ -48,6 +48,7 @@ import { transformTimelineItemToUnifiedRows } from '../utils'; import { TimelineEventDetailRow } from './timeline_event_detail_row'; import { CustomTimelineDataGridBody } from './custom_timeline_data_grid_body'; import { TIMELINE_EVENT_DETAIL_ROW_ID } from '../../body/constants'; +import { DocumentEventTypes } from '../../../../../common/lib/telemetry/types'; export const SAMPLE_SIZE_SETTING = 500; const DataGridMemoized = React.memo(UnifiedDataTable); @@ -165,7 +166,7 @@ export const TimelineDataTableComponent: React.FC = memo( }, }, }); - telemetry.reportDetailsFlyoutOpened({ + telemetry.reportEvent(DocumentEventTypes.DetailsFlyoutOpened, { location: timelineId, panel: 'right', }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/default_headers.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/default_headers.tsx deleted file mode 100644 index a0cf9d6355b9..000000000000 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/default_headers.tsx +++ /dev/null @@ -1,53 +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 { ColumnHeaderOptions, ColumnHeaderType } from '../../../../../common/types'; -import { - DEFAULT_COLUMN_MIN_WIDTH, - DEFAULT_UNIFIED_TABLE_DATE_COLUMN_MIN_WIDTH, -} from '../body/constants'; - -export const defaultColumnHeaderType: ColumnHeaderType = 'not-filtered'; - -export const defaultUdtHeaders: ColumnHeaderOptions[] = [ - { - columnHeaderType: defaultColumnHeaderType, - id: '@timestamp', - initialWidth: DEFAULT_UNIFIED_TABLE_DATE_COLUMN_MIN_WIDTH, - esTypes: ['date'], - type: 'date', - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'message', - initialWidth: DEFAULT_COLUMN_MIN_WIDTH * 2, - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'event.category', - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'event.action', - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'host.name', - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'source.ip', - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'destination.ip', - }, - { - columnHeaderType: defaultColumnHeaderType, - id: 'user.name', - }, -]; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.test.tsx index 9703efd8d5bb..c660893ba379 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.test.tsx @@ -32,7 +32,7 @@ import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_ex import { TimelineTabs } from '@kbn/securitysolution-data-table'; import { DataLoadingState } from '@kbn/unified-data-table'; import { getColumnHeaders } from '../body/column_headers/helpers'; -import { defaultUdtHeaders } from './default_headers'; +import { defaultUdtHeaders } from '../body/column_headers/default_headers'; import type { ColumnHeaderType } from '../../../../../common/types'; jest.mock('../../../containers', () => ({ @@ -45,10 +45,6 @@ jest.mock('../../fields_browser', () => ({ useFieldBrowserOptions: jest.fn(), })); -jest.mock('../body/events', () => ({ - Events: () => <>, -})); - jest.mock('../../../../sourcerer/containers'); jest.mock('../../../../sourcerer/containers/use_signal_helpers', () => ({ useSignalHelpers: () => ({ signalIndexNeedsInit: false }), diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.tsx index 7d89da9002ba..112886f93ca3 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.tsx @@ -31,7 +31,6 @@ import { withDataView } from '../../../../common/components/with_data_view'; import { EventDetailsWidthProvider } from '../../../../common/components/events_viewer/event_details_width_context'; import type { TimelineItem } from '../../../../../common/search_strategy'; import { useKibana } from '../../../../common/lib/kibana'; -import { defaultHeaders } from '../body/column_headers/default_headers'; import type { ColumnHeaderOptions, OnChangePage, @@ -47,7 +46,7 @@ import { TimelineResizableLayout } from './resizable_layout'; import TimelineDataTable from './data_table'; import { timelineActions } from '../../../store'; import { getFieldsListCreationOptions } from './get_fields_list_creation_options'; -import { defaultUdtHeaders } from './default_headers'; +import { defaultUdtHeaders } from '../body/column_headers/default_headers'; import { getTimelineShowStatusByIdSelector } from '../../../store/selectors'; const TimelineBodyContainer = styled.div.attrs(({ className = '' }) => ({ @@ -291,7 +290,7 @@ const UnifiedTimelineComponent: React.FC = ({ (columnId: string) => { dispatch( timelineActions.upsertColumn({ - column: getColumnHeader(columnId, defaultHeaders), + column: getColumnHeader(columnId, defaultUdtHeaders), id: timelineId, index: 1, }) diff --git a/x-pack/plugins/security_solution/public/timelines/hooks/use_create_timeline.test.tsx b/x-pack/plugins/security_solution/public/timelines/hooks/use_create_timeline.test.tsx index e8e2fe9dbbad..a4c054371a31 100644 --- a/x-pack/plugins/security_solution/public/timelines/hooks/use_create_timeline.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/hooks/use_create_timeline.test.tsx @@ -18,7 +18,7 @@ import { appActions } from '../../common/store/app'; import { SourcererScopeName } from '../../sourcerer/store/model'; import { InputsModelId } from '../../common/store/inputs/constants'; import { TestProviders, mockGlobalState } from '../../common/mock'; -import { defaultUdtHeaders } from '../components/timeline/unified_components/default_headers'; +import { defaultUdtHeaders } from '../components/timeline/body/column_headers/default_headers'; jest.mock('../../common/components/discover_in_timeline/use_discover_in_timeline_context'); jest.mock('../../common/containers/use_global_time', () => { diff --git a/x-pack/plugins/security_solution/public/timelines/hooks/use_create_timeline.tsx b/x-pack/plugins/security_solution/public/timelines/hooks/use_create_timeline.tsx index 527f372c1a44..2f80e969cab5 100644 --- a/x-pack/plugins/security_solution/public/timelines/hooks/use_create_timeline.tsx +++ b/x-pack/plugins/security_solution/public/timelines/hooks/use_create_timeline.tsx @@ -19,7 +19,7 @@ import { SourcererScopeName } from '../../sourcerer/store/model'; import { appActions } from '../../common/store/app'; import type { TimeRange } from '../../common/store/inputs/model'; import { useDiscoverInTimelineContext } from '../../common/components/discover_in_timeline/use_discover_in_timeline_context'; -import { defaultUdtHeaders } from '../components/timeline/unified_components/default_headers'; +import { defaultUdtHeaders } from '../components/timeline/body/column_headers/default_headers'; import { timelineDefaults } from '../store/defaults'; export interface UseCreateTimelineParams { diff --git a/x-pack/plugins/security_solution/public/timelines/store/defaults.ts b/x-pack/plugins/security_solution/public/timelines/store/defaults.ts index dd9b811e144e..e4fd97cd5053 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/defaults.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/defaults.ts @@ -12,10 +12,9 @@ import { RowRendererIdEnum, } from '../../../common/api/timeline'; -import { defaultHeaders } from '../components/timeline/body/column_headers/default_headers'; import { normalizeTimeRange } from '../../common/utils/normalize_time_range'; import type { SubsetTimelineModel, TimelineModel } from './model'; -import { defaultUdtHeaders } from '../components/timeline/unified_components/default_headers'; +import { defaultUdtHeaders } from '../components/timeline/body/column_headers/default_headers'; // normalizeTimeRange uses getTimeRangeSettings which cannot be used outside Kibana context if the uiSettings is not false const { from: start, to: end } = normalizeTimeRange({ from: '', to: '' }, false); @@ -109,7 +108,7 @@ export const timelineDefaults: SubsetTimelineModel & }; export const getTimelineManageDefaults = (id: string) => ({ - defaultColumns: defaultHeaders, + defaultColumns: defaultUdtHeaders, documentType: '', selectAll: false, id, diff --git a/x-pack/plugins/security_solution/public/timelines/store/helpers.test.ts b/x-pack/plugins/security_solution/public/timelines/store/helpers.test.ts index 4503d1026d7c..b0067d6d0d9f 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/helpers.test.ts @@ -18,7 +18,10 @@ import type { DataProvidersAnd, } from '../components/timeline/data_providers/data_provider'; import { IS_OPERATOR } from '../components/timeline/data_providers/data_provider'; -import { defaultColumnHeaderType } from '../components/timeline/body/column_headers/default_headers'; +import { + defaultUdtHeaders, + defaultColumnHeaderType, +} from '../components/timeline/body/column_headers/default_headers'; import { DEFAULT_COLUMN_MIN_WIDTH, RESIZED_COLUMN_MIN_WITH, @@ -50,7 +53,6 @@ import type { TimelineModel } from './model'; import { timelineDefaults } from './defaults'; import type { TimelineById } from './types'; import { Direction } from '../../../common/search_strategy'; -import { defaultUdtHeaders } from '../components/timeline/unified_components/default_headers'; jest.mock('../../common/utils/normalize_time_range'); jest.mock('../../common/utils/default_date_settings', () => { diff --git a/x-pack/plugins/security_solution/public/timelines/store/helpers.ts b/x-pack/plugins/security_solution/public/timelines/store/helpers.ts index b87646544974..a9566c22a814 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/helpers.ts +++ b/x-pack/plugins/security_solution/public/timelines/store/helpers.ts @@ -10,7 +10,6 @@ import { v4 as uuidv4 } from 'uuid'; import type { Filter } from '@kbn/es-query'; import type { SessionViewConfig } from '../../../common/types'; import type { TimelineNonEcsData } from '../../../common/search_strategy'; -import type { Sort } from '../components/timeline/body/sort'; import type { DataProvider, QueryOperator, @@ -23,15 +22,16 @@ import { TimelineStatusEnum, TimelineTypeEnum, } from '../../../common/api/timeline'; +import { TimelineId } from '../../../common/types/timeline'; import type { ColumnHeaderOptions, TimelineEventsType, SerializedFilterQuery, TimelinePersistInput, SortColumnTimeline, + SortColumnTimeline as Sort, } from '../../../common/types/timeline'; import type { RowRendererId, TimelineType } from '../../../common/api/timeline'; -import { TimelineId } from '../../../common/types/timeline'; import { normalizeTimeRange } from '../../common/utils/normalize_time_range'; import { getTimelineManageDefaults, timelineDefaults } from './defaults'; import type { KqlMode, TimelineModel } from './model'; diff --git a/x-pack/plugins/security_solution/public/types.ts b/x-pack/plugins/security_solution/public/types.ts index 6ac8b349b74c..55fce6a46dba 100644 --- a/x-pack/plugins/security_solution/public/types.ts +++ b/x-pack/plugins/security_solution/public/types.ts @@ -84,7 +84,6 @@ import type { Assets } from './assets'; import type { Investigations } from './investigations'; import type { MachineLearning } from './machine_learning'; -import type { TelemetryClientStart } from './common/lib/telemetry'; import type { Dashboards } from './dashboards'; import type { BreadcrumbsNav } from './common/breadcrumbs/types'; import type { TopValuesPopoverService } from './app/components/top_values_popover/top_values_popover_service'; @@ -93,6 +92,7 @@ import type { SetComponents, GetComponents$ } from './contract_components'; import type { ConfigSettings } from '../common/config_settings'; import type { OnboardingService } from './onboarding/service'; import type { SolutionNavigation } from './app/solution_navigation/solution_navigation'; +import type { TelemetryServiceStart } from './common/lib/telemetry'; export interface SetupPlugins { cloud?: CloudSetup; @@ -188,7 +188,7 @@ export type StartServices = CoreStart & getPluginWrapper: () => typeof SecuritySolutionTemplateWrapper; }; contentManagement: ContentManagementPublicStart; - telemetry: TelemetryClientStart; + telemetry: TelemetryServiceStart; customDataService: DataPublicPluginStart; topValuesPopover: TopValuesPopoverService; timelineDataService: DataPublicPluginStart; diff --git a/x-pack/plugins/security_solution/scripts/junit_transformer/lib.ts b/x-pack/plugins/security_solution/scripts/junit_transformer/lib.ts index 725baa689cd2..e09a057978bc 100644 --- a/x-pack/plugins/security_solution/scripts/junit_transformer/lib.ts +++ b/x-pack/plugins/security_solution/scripts/junit_transformer/lib.ts @@ -18,6 +18,20 @@ import { PathReporter } from 'io-ts/lib/PathReporter'; import globby from 'globby'; import del from 'del'; +// Function to remove specific fields from an XML object in order to +// compare them as strings. +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function removeFields(obj: any, fieldsToRemove: string[]): any { + for (const key in obj) { + if (fieldsToRemove.includes(key)) { + delete obj[key]; + } else if (typeof obj[key] === 'object') { + obj[key] = removeFields(obj[key], fieldsToRemove); // Recursively remove fields + } + } + return obj; +} + /** * Updates the `name` and `classname` attributes of each testcase. * `name` will have the value of `classname` appended to it. This makes sense because they each contain part of the bdd spec. @@ -174,6 +188,10 @@ export async function command({ flags, log }: CommandArgs) { throw createFlagError('please provide a single --reportName flag'); } + // Going to be used in order to store results as string in order to compare + // and remove duplicated reports. + const xmlResultFiles: string[] = []; + for (const path of await globby(flags.pathPattern)) { // Read the file const source: string = await fs.readFile(path, 'utf8'); @@ -242,6 +260,26 @@ ${boilerplate} rootDirectory: flags.rootDirectory, }); + // We need to check if a XML Junit report is duplicate + // Only if we remove the time and timestamp and the rest of the + // report as a string is completely identical. + const fieldsToRemove = ['time', 'timestamp']; + const tempReport = await parseStringPromise(reportString); + const truncatedReport = removeFields(tempReport, fieldsToRemove); + + // Rebuild the XML to compare (optional, if you want to compare XML strings) + const builder = new Builder(); + const rebuildComparableReport = builder.buildObject(truncatedReport); + + // Compare the cleaned and rebuilt XML objects or strings + if (xmlResultFiles.includes(rebuildComparableReport)) { + // If the report is a duplicate, we need to remove the file + // in order to be excluded from the uploaded results. + await del(path, { force: true }); + continue; + } + xmlResultFiles.push(rebuildComparableReport); + // If the writeInPlace flag was passed, overwrite the original file, otherwise log the output to stdout if (flags.writeInPlace) { log.info(`Wrote transformed junit report to ${path}`); diff --git a/x-pack/plugins/security_solution/server/assistant/tools/knowledge_base/knowledge_base_write_tool.ts b/x-pack/plugins/security_solution/server/assistant/tools/knowledge_base/knowledge_base_write_tool.ts index 4069eeeef5b9..3ae47afbf05b 100644 --- a/x-pack/plugins/security_solution/server/assistant/tools/knowledge_base/knowledge_base_write_tool.ts +++ b/x-pack/plugins/security_solution/server/assistant/tools/knowledge_base/knowledge_base_write_tool.ts @@ -12,10 +12,12 @@ import type { AIAssistantKnowledgeBaseDataClient } from '@kbn/elastic-assistant- import { DocumentEntryType } from '@kbn/elastic-assistant-common'; import type { KnowledgeBaseEntryCreateProps } from '@kbn/elastic-assistant-common'; import type { LegacyKnowledgeBaseEntryCreateProps } from '@kbn/elastic-assistant-plugin/server/ai_assistant_data_clients/knowledge_base/create_knowledge_base_entry'; +import type { AnalyticsServiceSetup } from '@kbn/core-analytics-server'; import { APP_UI_ID } from '../../../../common'; export interface KnowledgeBaseWriteToolParams extends AssistantToolParams { kbDataClient: AIAssistantKnowledgeBaseDataClient; + telemetry: AnalyticsServiceSetup; } const toolDetails = { @@ -34,7 +36,7 @@ export const KNOWLEDGE_BASE_WRITE_TOOL: AssistantTool = { getTool(params: AssistantToolParams) { if (!this.isSupported(params)) return null; - const { kbDataClient, logger } = params as KnowledgeBaseWriteToolParams; + const { telemetry, kbDataClient, logger } = params as KnowledgeBaseWriteToolParams; if (kbDataClient == null) return null; return new DynamicStructuredTool({ @@ -77,7 +79,7 @@ export const KNOWLEDGE_BASE_WRITE_TOOL: AssistantTool = { }; logger.debug(() => `knowledgeBaseEntry\n ${JSON.stringify(knowledgeBaseEntry, null, 2)}`); - const resp = await kbDataClient.createKnowledgeBaseEntry({ knowledgeBaseEntry }); + const resp = await kbDataClient.createKnowledgeBaseEntry({ knowledgeBaseEntry, telemetry }); if (resp == null) { return "I'm sorry, but I was unable to add this entry to your knowledge base."; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/audit_log.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/audit_log.ts index 196ffc71162d..8ba1de0bb70d 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/audit_log.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/audit_log.ts @@ -27,7 +27,12 @@ export function registerActionAuditLogRoutes( .get({ access: 'public', path: ENDPOINT_ACTION_LOG_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/details.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/details.ts index 96b466a251cf..1d524b08aefc 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/details.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/details.ts @@ -32,7 +32,12 @@ export const registerActionDetailsRoutes = ( .get({ access: 'public', path: ACTION_DETAILS_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_download_handler.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_download_handler.ts index 2e16c57886f7..29aa6f4bba3d 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_download_handler.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_download_handler.ts @@ -38,7 +38,12 @@ export const registerActionFileDownloadRoutes = ( // we need to enable setting the version number via query params enableQueryVersion: true, path: ACTION_AGENT_FILE_DOWNLOAD_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_info_handler.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_info_handler.ts index 1cb4e95e1eaf..63118a64fc45 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_info_handler.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/file_info_handler.ts @@ -74,7 +74,12 @@ export const registerActionFileInfoRoute = ( .get({ access: 'public', path: ACTION_AGENT_FILE_INFO_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/list.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/list.ts index a858909f5e2e..05e5d77eb945 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/list.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/list.ts @@ -30,7 +30,12 @@ export function registerActionListRoutes( .get({ access: 'public', path: BASE_ENDPOINT_ACTION_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts index b6eb2376bd1c..0fc90c7589b9 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts @@ -80,7 +80,12 @@ export function registerResponseActionRoutes( .post({ access: 'public', path: ISOLATE_HOST_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { @@ -99,7 +104,12 @@ export function registerResponseActionRoutes( .post({ access: 'public', path: UNISOLATE_HOST_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { @@ -119,7 +129,12 @@ export function registerResponseActionRoutes( .post({ access: 'public', path: ISOLATE_HOST_ROUTE_V2, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { @@ -139,7 +154,12 @@ export function registerResponseActionRoutes( .post({ access: 'public', path: UNISOLATE_HOST_ROUTE_V2, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { @@ -159,7 +179,12 @@ export function registerResponseActionRoutes( .post({ access: 'public', path: KILL_PROCESS_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { @@ -182,7 +207,12 @@ export function registerResponseActionRoutes( .post({ access: 'public', path: SUSPEND_PROCESS_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { @@ -205,7 +235,12 @@ export function registerResponseActionRoutes( .post({ access: 'public', path: GET_PROCESSES_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { @@ -225,7 +260,12 @@ export function registerResponseActionRoutes( .post({ access: 'public', path: GET_FILE_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { @@ -245,7 +285,12 @@ export function registerResponseActionRoutes( .post({ access: 'public', path: EXECUTE_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { @@ -265,9 +310,14 @@ export function registerResponseActionRoutes( .post({ access: 'public', path: UPLOAD_ROUTE, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, options: { authRequired: true, - tags: ['access:securitySolution'], + body: { accepts: ['multipart/form-data'], output: 'stream', @@ -293,7 +343,12 @@ export function registerResponseActionRoutes( .post({ access: 'public', path: SCAN_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/state.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/state.ts index 3ea4d9fa3575..c2d5b850d6bb 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/state.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/state.ts @@ -32,7 +32,12 @@ export function registerActionStateRoutes( .get({ access: 'public', path: ACTION_STATE_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.ts index 6172bf07d232..8a245dfb451e 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/status.ts @@ -29,7 +29,12 @@ export function registerActionStatusRoutes( .get({ access: 'public', path: ACTION_STATUS_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/agent/agent_status_handler.ts b/x-pack/plugins/security_solution/server/endpoint/routes/agent/agent_status_handler.ts index e6ea2f759578..7ca24156b45f 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/agent/agent_status_handler.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/agent/agent_status_handler.ts @@ -27,7 +27,12 @@ export const registerAgentStatusRoute = ( .get({ access: 'internal', path: AGENT_STATUS_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts index 2f6e46d1d772..3f028719fe5a 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts @@ -54,7 +54,12 @@ export function registerEndpointRoutes( .get({ access: 'public', path: HOST_METADATA_LIST_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { @@ -94,7 +99,12 @@ export function registerEndpointRoutes( .get({ access: 'public', path: METADATA_TRANSFORMS_STATUS_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} deprecated: true, }) @@ -114,7 +124,12 @@ export function registerEndpointRoutes( .get({ access: 'internal', path: METADATA_TRANSFORMS_STATUS_INTERNAL_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts index 00054964e440..6010c5655727 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts @@ -240,8 +240,8 @@ describe('test endpoint routes', () => { }); expect(routeConfig.options).toEqual({ authRequired: true, - tags: ['access:securitySolution'], }); + expect(routeConfig.security?.authz).toEqual({ requiredPrivileges: ['securitySolution'] }); expect(mockResponse.ok).toBeCalled(); const endpointResultList = mockResponse.ok.mock.calls[0][0]?.body as MetadataListResponse; expect(endpointResultList.data.length).toEqual(1); @@ -614,8 +614,8 @@ describe('test endpoint routes', () => { expect(esClientMock.transform.getTransformStats).toHaveBeenCalledTimes(1); expect(routeConfig.options).toEqual({ authRequired: true, - tags: ['access:securitySolution'], }); + expect(routeConfig.security?.authz).toEqual({ requiredPrivileges: ['securitySolution'] }); expect(mockResponse.ok).toBeCalled(); const response = mockResponse.ok.mock.calls[0][0]?.body as TransformGetTransformStatsResponse; expect(response.count).toEqual(expectedResponse.count); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/protection_updates_note/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/protection_updates_note/index.ts index 7b28ccfcf9fe..4355684407bb 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/protection_updates_note/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/protection_updates_note/index.ts @@ -25,7 +25,12 @@ export function registerProtectionUpdatesNoteRoutes( .post({ access: 'public', path: PROTECTION_UPDATES_NOTE_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { @@ -45,7 +50,12 @@ export function registerProtectionUpdatesNoteRoutes( .get({ access: 'public', path: PROTECTION_UPDATES_NOTE_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/suggestions/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/suggestions/index.ts index 677fb004ee86..bbee33114534 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/suggestions/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/suggestions/index.ts @@ -42,7 +42,12 @@ export function registerEndpointSuggestionsRoutes( .post({ access: 'public', path: SUGGESTIONS_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} deprecated: true, }) @@ -64,7 +69,12 @@ export function registerEndpointSuggestionsRoutes( .post({ access: 'internal', path: SUGGESTIONS_INTERNAL_ROUTE, - options: { authRequired: true, tags: ['access:securitySolution'] }, + security: { + authz: { + requiredPrivileges: ['securitySolution'], + }, + }, + options: { authRequired: true }, }) .addVersion( { diff --git a/x-pack/plugins/security_solution/server/lib/dashboards/routes/get_dashboards_by_tags.ts b/x-pack/plugins/security_solution/server/lib/dashboards/routes/get_dashboards_by_tags.ts index e7a3ebf9a7f1..dda4a6af5d22 100644 --- a/x-pack/plugins/security_solution/server/lib/dashboards/routes/get_dashboards_by_tags.ts +++ b/x-pack/plugins/security_solution/server/lib/dashboards/routes/get_dashboards_by_tags.ts @@ -7,7 +7,7 @@ import type { Logger } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; -import type { DashboardAttributes } from '@kbn/dashboard-plugin/common'; +import type { DashboardSavedObjectAttributes } from '@kbn/dashboard-plugin/server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { INTERNAL_DASHBOARDS_URL } from '../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../types'; @@ -36,7 +36,7 @@ export const getDashboardsByTagsRoute = (router: SecuritySolutionPluginRouter, l const { tagIds } = request.body; try { - const dashboardsResponse = await savedObjectsClient.find({ + const dashboardsResponse = await savedObjectsClient.find({ type: 'dashboard', hasReference: tagIds.map((id) => ({ id, type: 'tag' })), }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/create_upgradeable_rules_payload.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/create_upgradeable_rules_payload.ts index b25320e1131e..7f9f66d1019c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/create_upgradeable_rules_payload.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/create_upgradeable_rules_payload.ts @@ -26,6 +26,7 @@ import { getValueForField } from './get_value_for_field'; interface CreateModifiedPrebuiltRuleAssetsProps { upgradeableRules: RuleTriad[]; requestBody: PerformRuleUpgradeRequestBody; + prebuiltRulesCustomizationEnabled: boolean; } interface ProcessedRules { @@ -36,9 +37,13 @@ interface ProcessedRules { export const createModifiedPrebuiltRuleAssets = ({ upgradeableRules, requestBody, + prebuiltRulesCustomizationEnabled, }: CreateModifiedPrebuiltRuleAssetsProps) => { return withSecuritySpanSync(createModifiedPrebuiltRuleAssets.name, () => { - const { pick_version: globalPickVersion = PickVersionValuesEnum.MERGED, mode } = requestBody; + const defaultPickVersion = prebuiltRulesCustomizationEnabled + ? PickVersionValuesEnum.MERGED + : PickVersionValuesEnum.TARGET; + const { pick_version: globalPickVersion = defaultPickVersion, mode } = requestBody; const { modifiedPrebuiltRuleAssets, processingErrors } = upgradeableRules.reduce( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/perform_rule_upgrade_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/perform_rule_upgrade_route.ts index 085c41db3a5d..c8b5d459f678 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/perform_rule_upgrade_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/perform_rule_upgrade_route.ts @@ -25,8 +25,12 @@ import { PREBUILT_RULES_OPERATION_SOCKET_TIMEOUT_MS } from '../../constants'; import { getUpgradeableRules } from './get_upgradeable_rules'; import { createModifiedPrebuiltRuleAssets } from './create_upgradeable_rules_payload'; import { getRuleGroups } from '../../model/rule_groups/get_rule_groups'; +import type { ConfigType } from '../../../../../config'; -export const performRuleUpgradeRoute = (router: SecuritySolutionPluginRouter) => { +export const performRuleUpgradeRoute = ( + router: SecuritySolutionPluginRouter, + config: ConfigType +) => { router.versioned .post({ access: 'internal', @@ -75,10 +79,12 @@ export const performRuleUpgradeRoute = (router: SecuritySolutionPluginRouter) => mode, }); + const { prebuiltRulesCustomizationEnabled } = config.experimentalFeatures; const { modifiedPrebuiltRuleAssets, processingErrors } = createModifiedPrebuiltRuleAssets( { upgradeableRules, requestBody: request.body, + prebuiltRulesCustomizationEnabled, } ); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/register_routes.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/register_routes.ts index c9871f86a43e..2a2cf8823763 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/register_routes.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/register_routes.ts @@ -6,7 +6,7 @@ */ import type { SecuritySolutionPluginRouter } from '../../../../types'; - +import type { ConfigType } from '../../../../config'; import { getPrebuiltRulesAndTimelinesStatusRoute } from './get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route'; import { getPrebuiltRulesStatusRoute } from './get_prebuilt_rules_status/get_prebuilt_rules_status_route'; import { installPrebuiltRulesAndTimelinesRoute } from './install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route'; @@ -16,7 +16,10 @@ import { performRuleInstallationRoute } from './perform_rule_installation/perfor import { performRuleUpgradeRoute } from './perform_rule_upgrade/perform_rule_upgrade_route'; import { bootstrapPrebuiltRulesRoute } from './bootstrap_prebuilt_rules/bootstrap_prebuilt_rules'; -export const registerPrebuiltRulesRoutes = (router: SecuritySolutionPluginRouter) => { +export const registerPrebuiltRulesRoutes = ( + router: SecuritySolutionPluginRouter, + config: ConfigType +) => { // Legacy endpoints that we're going to deprecate getPrebuiltRulesAndTimelinesStatusRoute(router); installPrebuiltRulesAndTimelinesRoute(router); @@ -24,7 +27,7 @@ export const registerPrebuiltRulesRoutes = (router: SecuritySolutionPluginRouter // New endpoints for the rule upgrade and installation workflows getPrebuiltRulesStatusRoute(router); performRuleInstallationRoute(router); - performRuleUpgradeRoute(router); + performRuleUpgradeRoute(router, config); reviewRuleInstallationRoute(router); reviewRuleUpgradeRoute(router); bootstrapPrebuiltRulesRoute(router); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/enrich_signal_threat_matches.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/enrich_signal_threat_matches.ts index 8f98eab1a93e..0d9882fe8aec 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/enrich_signal_threat_matches.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/enrich_signal_threat_matches.ts @@ -24,8 +24,10 @@ export const groupAndMergeSignalMatches = (signalHits: SignalSourceHit[]): Signa if (existingSignalHit == null) { acc[signalId] = signalHit; } else { - const existingQueries = existingSignalHit?.matched_queries ?? []; - const newQueries = signalHit.matched_queries ?? []; + const existingQueries = Array.isArray(existingSignalHit?.matched_queries) + ? existingSignalHit.matched_queries + : []; + const newQueries = Array.isArray(signalHit.matched_queries) ? signalHit.matched_queries : []; existingSignalHit.matched_queries = [...existingQueries, ...newQueries]; acc[signalId] = existingSignalHit; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/get_signals_map_from_threat_index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/get_signals_map_from_threat_index.ts index 309516a57335..9694d37aab0a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/get_signals_map_from_threat_index.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/get_signals_map_from_threat_index.ts @@ -90,7 +90,9 @@ export async function getSignalsQueryMapFromThreatIndex( while (maxThreatsReachedMap.size < eventsCount && threatList?.hits.hits.length > 0) { threatList.hits.hits.forEach((threatHit) => { - const matchedQueries = threatHit?.matched_queries || []; + const matchedQueries = Array.isArray(threatHit?.matched_queries) + ? threatHit.matched_queries + : []; matchedQueries.forEach((matchedQuery) => { const decodedQuery = decodeThreatMatchNamedQuery(matchedQuery); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/utils.ts index da72d121c371..347ea5d1d94c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/threat_mapping/utils.ts @@ -189,7 +189,9 @@ export const decodeThreatMatchNamedQuery = (encoded: string): DecodedThreatNamed export const extractNamedQueries = ( hit: SignalSourceHit | ThreatListItem ): DecodedThreatNamedQuery[] => - hit.matched_queries?.map((match) => decodeThreatMatchNamedQuery(match)) ?? []; + Array.isArray(hit.matched_queries) + ? hit.matched_queries.map((match) => decodeThreatMatchNamedQuery(match)) + : []; export const buildExecutionIntervalValidator: (interval: string) => () => void = (interval) => { const intervalDuration = parseInterval(interval); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/entity_index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/entity_index.ts index 7bc139ea08ad..6fb5935618df 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/entity_index.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/entity_index.ts @@ -8,6 +8,7 @@ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import type { EntityType } from '../../../../../common/api/entity_analytics'; import { getEntitiesIndexName } from '../utils'; +import { createOrUpdateIndex } from '../../utils/create_or_update_index'; interface Options { entityType: EntityType; @@ -17,18 +18,13 @@ interface Options { } export const createEntityIndex = async ({ entityType, esClient, namespace, logger }: Options) => { - try { - await esClient.indices.create({ + await createOrUpdateIndex({ + esClient, + logger, + options: { index: getEntitiesIndexName(entityType, namespace), - body: {}, - }); - } catch (e) { - if (e.meta.body.error.type === 'resource_already_exists_exception') { - logger.debug(`Index for ${entityType} already exists, skipping creation.`); - } else { - throw e; - } - } + }, + }); }; export const deleteEntityIndex = ({ entityType, esClient, namespace }: Options) => diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/constants.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/constants.ts index 9f9dbb836498..43730fa06357 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/constants.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/constants.ts @@ -15,10 +15,10 @@ export const BASE_ENTITY_INDEX_MAPPING: MappingProperties = { type: 'keyword', }, 'entity.name': { - type: 'text', + type: 'keyword', fields: { text: { - type: 'keyword', + type: 'match_only_text', }, }, }, diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/entity_types/host.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/entity_types/host.ts index db9266997743..5abeffd05b1f 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/entity_types/host.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/entity_types/host.ts @@ -18,7 +18,17 @@ export const getHostUnitedDefinition: UnitedDefinitionBuilder = (fieldHistoryLen collect({ field: 'host.domain' }), collect({ field: 'host.hostname' }), collect({ field: 'host.id' }), - collect({ field: 'host.os.name' }), + collect({ + field: 'host.os.name', + mapping: { + type: 'keyword', + fields: { + text: { + type: 'match_only_text', + }, + }, + }, + }), collect({ field: 'host.os.type' }), collect({ field: 'host.ip', diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/entity_types/user.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/entity_types/user.ts index 632d1a685b99..3881425df77c 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/entity_types/user.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/entity_types/user.ts @@ -16,7 +16,17 @@ export const getUserUnitedDefinition: UnitedDefinitionBuilder = (fieldHistoryLen fields: [ collect({ field: 'user.domain' }), collect({ field: 'user.email' }), - collect({ field: 'user.full_name' }), + collect({ + field: 'user.full_name', + mapping: { + type: 'keyword', + fields: { + text: { + type: 'match_only_text', + }, + }, + }, + }), collect({ field: 'user.hash' }), collect({ field: 'user.id' }), collect({ field: 'user.roles' }), diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/get_united_definition.test.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/get_united_definition.test.ts index fa443ffa9404..07c011b4791e 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/get_united_definition.test.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/get_united_definition.test.ts @@ -32,10 +32,10 @@ describe('getUnitedEntityDefinition', () => { "entity.name": Object { "fields": Object { "text": Object { - "type": "keyword", + "type": "match_only_text", }, }, - "type": "text", + "type": "keyword", }, "entity.source": Object { "type": "keyword", @@ -59,9 +59,19 @@ describe('getUnitedEntityDefinition', () => { "type": "keyword", }, "host.name": Object { + "fields": Object { + "text": Object { + "type": "match_only_text", + }, + }, "type": "keyword", }, "host.os.name": Object { + "fields": Object { + "text": Object { + "type": "match_only_text", + }, + }, "type": "keyword", }, "host.os.type": Object { @@ -335,10 +345,10 @@ describe('getUnitedEntityDefinition', () => { "entity.name": Object { "fields": Object { "text": Object { - "type": "keyword", + "type": "match_only_text", }, }, - "type": "text", + "type": "keyword", }, "entity.source": Object { "type": "keyword", @@ -350,6 +360,11 @@ describe('getUnitedEntityDefinition', () => { "type": "keyword", }, "user.full_name": Object { + "fields": Object { + "text": Object { + "type": "match_only_text", + }, + }, "type": "keyword", }, "user.hash": Object { @@ -359,6 +374,11 @@ describe('getUnitedEntityDefinition', () => { "type": "keyword", }, "user.name": Object { + "fields": Object { + "text": Object { + "type": "match_only_text", + }, + }, "type": "keyword", }, "user.risk.calculated_level": Object { diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/united_entity_definition.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/united_entity_definition.ts index eced765c7519..fc7430ebb180 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/united_entity_definition.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/united_entity_definitions/united_entity_definition.ts @@ -94,6 +94,11 @@ export class UnitedEntityDefinition { ...BASE_ENTITY_INDEX_MAPPING, [identityField]: { type: 'keyword', + fields: { + text: { + type: 'match_only_text', + }, + }, }, }; @@ -107,6 +112,11 @@ export class UnitedEntityDefinition { properties[identityField] = { type: 'keyword', + fields: { + text: { + type: 'match_only_text', + }, + }, }; return { diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/create_or_update_index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/create_or_update_index.ts index f9525e14ac6c..b6e49017c95a 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/create_or_update_index.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/utils/create_or_update_index.ts @@ -51,7 +51,16 @@ export const createOrUpdateIndex = async ({ ); } } else { - return esClient.indices.create(options); + try { + await esClient.indices.create(options); + } catch (err) { + // If the index already exists, we can ignore the error + if (err?.meta?.body?.error?.type === 'resource_already_exists_exception') { + logger.info(`${options.index} already exists`); + } else { + throw err; + } + } } } catch (err) { const error = transformError(err); diff --git a/x-pack/plugins/security_solution/server/lib/security_integrations/cribl/routes/index.ts b/x-pack/plugins/security_solution/server/lib/security_integrations/cribl/routes/index.ts index 02ea25244007..fc531525e4e8 100644 --- a/x-pack/plugins/security_solution/server/lib/security_integrations/cribl/routes/index.ts +++ b/x-pack/plugins/security_solution/server/lib/security_integrations/cribl/routes/index.ts @@ -17,6 +17,13 @@ export const getFleetManagedIndexTemplatesRoute = (router: IRouter) => { .addVersion( { version: '1', + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization of the current user to the Elasticsearch index template API.', + }, + }, validate: {}, }, async (context, _request, response) => { diff --git a/x-pack/plugins/security_solution/server/routes/index.ts b/x-pack/plugins/security_solution/server/routes/index.ts index 8fb74afc770b..f7d5ce7afb3d 100644 --- a/x-pack/plugins/security_solution/server/routes/index.ts +++ b/x-pack/plugins/security_solution/server/routes/index.ts @@ -81,7 +81,7 @@ export const initRoutes = ( ) => { registerFleetIntegrationsRoutes(router); registerLegacyRuleActionsRoutes(router, logger); - registerPrebuiltRulesRoutes(router); + registerPrebuiltRulesRoutes(router, config); registerRuleExceptionsRoutes(router); registerManageExceptionsRoutes(router); registerRuleManagementRoutes(router, config, ml, logger); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/cti/event_enrichment/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/cti/event_enrichment/helpers.ts index e15aceb8a713..54af298d11a3 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/cti/event_enrichment/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/cti/event_enrichment/helpers.ts @@ -46,16 +46,19 @@ export const buildIndicatorShouldClauses = ( export const buildIndicatorEnrichments = (hits: estypes.SearchHit[]): CtiEnrichment[] => { return hits.flatMap(({ matched_queries: matchedQueries, ...hit }) => { return ( - matchedQueries?.reduce((enrichments, matchedQuery) => { - if (isValidEventField(matchedQuery)) { - enrichments.push({ - ...hit.fields, - ...buildIndicatorMatchedFields(hit, matchedQuery), - }); - } + (Array.isArray(matchedQueries) ? matchedQueries : [])?.reduce( + (enrichments, matchedQuery) => { + if (isValidEventField(matchedQuery)) { + enrichments.push({ + ...hit.fields, + ...buildIndicatorMatchedFields(hit, matchedQuery), + }); + } - return enrichments; - }, []) ?? [] + return enrichments; + }, + [] + ) ?? [] ); }); }; diff --git a/x-pack/plugins/serverless_observability/public/navigation_tree.ts b/x-pack/plugins/serverless_observability/public/navigation_tree.ts index 5df900ee4681..7501a75abe87 100644 --- a/x-pack/plugins/serverless_observability/public/navigation_tree.ts +++ b/x-pack/plugins/serverless_observability/public/navigation_tree.ts @@ -70,147 +70,258 @@ export const navigationTree: NavigationTreeDefinition = { link: 'slo', }, { - id: 'aiops', - title: 'AIOps', - link: 'ml:anomalyDetection', - renderAs: 'accordion', - spaceBefore: null, + link: 'observabilityAIAssistant', + title: i18n.translate('xpack.serverlessObservability.nav.aiAssistant', { + defaultMessage: 'AI Assistant', + }), + }, + { link: 'inventory', spaceBefore: 'm' }, + { + id: 'apm', + title: i18n.translate('xpack.serverlessObservability.nav.applications', { + defaultMessage: 'Applications', + }), + renderAs: 'panelOpener', children: [ { - title: i18n.translate('xpack.serverlessObservability.nav.ml.jobs', { - defaultMessage: 'Anomaly detection', - }), - link: 'ml:anomalyDetection', - id: 'ml:anomalyDetection', - renderAs: 'item', children: [ { - link: 'ml:singleMetricViewer', - }, - { - link: 'ml:anomalyExplorer', + link: 'apm:services', + title: i18n.translate('xpack.serverlessObservability.nav.apm.services', { + defaultMessage: 'Service inventory', + }), }, + { link: 'apm:traces' }, + { link: 'apm:dependencies' }, + { link: 'apm:settings' }, { - link: 'ml:settings', + id: 'synthetics', + title: i18n.translate('xpack.serverlessObservability.nav.synthetics', { + defaultMessage: 'Synthetics', + }), + children: [ + { + title: i18n.translate( + 'xpack.serverlessObservability.nav.synthetics.overviewItem', + { + defaultMessage: 'Overview', + } + ), + id: 'synthetics-overview', + link: 'synthetics:overview', + breadcrumbStatus: 'hidden', + }, + { + link: 'synthetics:certificates', + title: i18n.translate( + 'xpack.serverlessObservability.nav.synthetics.certificatesItem', + { + defaultMessage: 'TLS certificates', + } + ), + id: 'synthetics-certificates', + breadcrumbStatus: 'hidden', + }, + ], }, ], }, - { - title: i18n.translate('xpack.serverlessObservability.ml.logRateAnalysis', { - defaultMessage: 'Log rate analysis', - }), - link: 'ml:logRateAnalysis', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.includes(prepend('/app/ml/aiops/log_rate_analysis')); - }, - }, - { - title: i18n.translate('xpack.serverlessObservability.ml.changePointDetection', { - defaultMessage: 'Change point detection', - }), - link: 'ml:changePointDetections', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.includes(prepend('/app/ml/aiops/change_point_detection')); - }, - }, - { - title: i18n.translate('xpack.serverlessObservability.nav.ml.job.notifications', { - defaultMessage: 'Job notifications', - }), - link: 'ml:notifications', - }, ], }, - { link: 'inventory', spaceBefore: 'm' }, { - id: 'apm', - title: i18n.translate('xpack.serverlessObservability.nav.applications', { - defaultMessage: 'Applications', + id: 'metrics', + title: i18n.translate('xpack.serverlessObservability.nav.infrastructure', { + defaultMessage: 'Infrastructure', }), - link: 'apm:services', - renderAs: 'accordion', + renderAs: 'panelOpener', children: [ { - link: 'apm:services', - getIsActive: ({ pathNameSerialized }) => { - const regex = /app\/apm\/.*service.*/; - return regex.test(pathNameSerialized); - }, - }, - { - link: 'apm:traces', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/apm/traces')); - }, - }, - { - link: 'apm:dependencies', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/apm/dependencies')); - }, - }, - { - link: 'apm:settings', - sideNavStatus: 'hidden', // only to be considered in the breadcrumbs + children: [ + { + link: 'metrics:inventory', + title: i18n.translate( + 'xpack.serverlessObservability.nav.infrastructureInventory', + { + defaultMessage: 'Infrastructure inventory', + } + ), + }, + { link: 'metrics:hosts' }, + { link: 'metrics:settings' }, + { link: 'metrics:assetDetails' }, + ], }, ], }, { - id: 'metrics', - title: i18n.translate('xpack.serverlessObservability.nav.infrastructure', { - defaultMessage: 'Infrastructure', + id: 'machine_learning-landing', + renderAs: 'panelOpener', + title: i18n.translate('xpack.serverlessObservability.nav.machineLearning', { + defaultMessage: 'Machine learning', }), - link: 'metrics:inventory', - renderAs: 'accordion', children: [ { - link: 'metrics:inventory', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/metrics/inventory')); - }, + children: [ + { + link: 'ml:overview', + }, + { + link: 'ml:notifications', + }, + { + link: 'ml:memoryUsage', + title: i18n.translate( + 'xpack.serverlessObservability.nav.machineLearning.memoryUsage', + { + defaultMessage: 'Memory usage', + } + ), + }, + ], }, { - link: 'metrics:hosts', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/metrics/hosts')); - }, + id: 'category-anomaly_detection', + title: i18n.translate('xpack.serverlessObservability.nav.ml.anomaly_detection', { + defaultMessage: 'Anomaly detection', + }), + breadcrumbStatus: 'hidden', + children: [ + { + link: 'ml:anomalyDetection', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.anomaly_detection.jobs', + { + defaultMessage: 'Jobs', + } + ), + }, + { + link: 'ml:anomalyExplorer', + }, + { + link: 'ml:singleMetricViewer', + }, + { + link: 'ml:settings', + }, + { + link: 'ml:suppliedConfigurations', + }, + ], }, { - link: 'metrics:settings', - sideNavStatus: 'hidden', // only to be considered in the breadcrumbs + id: 'category-data_frame analytics', + title: i18n.translate('xpack.serverlessObservability.nav.ml.data_frame_analytics', { + defaultMessage: 'Data frame analytics', + }), + breadcrumbStatus: 'hidden', + children: [ + { + link: 'ml:dataFrameAnalytics', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.data_frame_analytics.jobs', + { + defaultMessage: 'Jobs', + } + ), + }, + { + link: 'ml:resultExplorer', + }, + { + link: 'ml:analyticsMap', + }, + ], }, { - link: 'metrics:assetDetails', - sideNavStatus: 'hidden', // only to be considered in the breadcrumbs + id: 'category-model_management', + title: i18n.translate('xpack.serverlessObservability.nav.ml.model_management', { + defaultMessage: 'Model management', + }), + breadcrumbStatus: 'hidden', + children: [ + { + link: 'ml:nodesOverview', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.model_management.trainedModels', + { + defaultMessage: 'Trained models', + } + ), + }, + ], }, - ], - }, - { - id: 'synthetics', - title: i18n.translate('xpack.serverlessObservability.nav.synthetics', { - defaultMessage: 'Synthetics', - }), - renderAs: 'accordion', - breadcrumbStatus: 'hidden', - children: [ { - title: i18n.translate('xpack.serverlessObservability.nav.synthetics.overviewItem', { - defaultMessage: 'Overview', + id: 'category-data_visualizer', + title: i18n.translate('xpack.serverlessObservability.nav.ml.data_visualizer', { + defaultMessage: 'Data visualizer', }), - id: 'synthetics-overview', - link: 'synthetics:overview', breadcrumbStatus: 'hidden', + children: [ + { + link: 'ml:fileUpload', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.data_visualizer.file_data_visualizer', + { + defaultMessage: 'File data visualizer', + } + ), + }, + { + link: 'ml:indexDataVisualizer', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.data_visualizer.data_view_data_visualizer', + { + defaultMessage: 'Data view data visualizer', + } + ), + }, + { + link: 'ml:dataDrift', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.data_visualizer.data_drift', + { + defaultMessage: 'Data drift', + } + ), + }, + ], }, { - link: 'synthetics:certificates', - title: i18n.translate( - 'xpack.serverlessObservability.nav.synthetics.certificatesItem', - { - defaultMessage: 'TLS Certificates', - } - ), - id: 'synthetics-certificates', + id: 'category-aiops_labs', + title: i18n.translate('xpack.serverlessObservability.nav.ml.aiops_labs', { + defaultMessage: 'Aiops labs', + }), breadcrumbStatus: 'hidden', + children: [ + { + link: 'ml:logRateAnalysis', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.aiops_labs.log_rate_analysis', + { + defaultMessage: 'Log rate analysis', + } + ), + }, + { + link: 'ml:logPatternAnalysis', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.aiops_labs.log_pattern_analysis', + { + defaultMessage: 'Log pattern analysis', + } + ), + }, + { + link: 'ml:changePointDetections', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.aiops_labs.change_point_detection', + { + defaultMessage: 'Change point detection', + } + ), + }, + ], }, ], }, diff --git a/x-pack/plugins/serverless_search/kibana.jsonc b/x-pack/plugins/serverless_search/kibana.jsonc index f7b404edb37b..cae0a693846f 100644 --- a/x-pack/plugins/serverless_search/kibana.jsonc +++ b/x-pack/plugins/serverless_search/kibana.jsonc @@ -35,6 +35,7 @@ "indexManagement", "searchConnectors", "searchInferenceEndpoints", + "searchPlayground", "usageCollection" ], "requiredBundles": ["kibanaReact"] diff --git a/x-pack/plugins/serverless_search/public/navigation_tree.ts b/x-pack/plugins/serverless_search/public/navigation_tree.ts index b0f5a4658e7d..066ab8e8c093 100644 --- a/x-pack/plugins/serverless_search/public/navigation_tree.ts +++ b/x-pack/plugins/serverless_search/public/navigation_tree.ts @@ -20,14 +20,6 @@ export const navigationTree = (): NavigationTreeDefinition => ({ isCollapsible: false, breadcrumbStatus: 'hidden', children: [ - { - id: 'home', - title: i18n.translate('xpack.serverlessSearch.nav.home', { - defaultMessage: 'Home', - }), - link: 'elasticsearchStart', - spaceBefore: 'm', - }, { id: 'data', title: i18n.translate('xpack.serverlessSearch.nav.data', { @@ -47,9 +39,8 @@ export const navigationTree = (): NavigationTreeDefinition => ({ pathNameSerialized.startsWith( prepend('/app/management/data/index_management/') ) || - pathNameSerialized.startsWith( - prepend('/app/elasticsearch/indices/index_details/') - ) + pathNameSerialized.startsWith(prepend('/app/elasticsearch/indices')) || + pathNameSerialized.startsWith(prepend('/app/elasticsearch/start')) ); }, }, diff --git a/x-pack/plugins/session_view/public/components/process_tree_node/buttons.tsx b/x-pack/plugins/session_view/public/components/process_tree_node/buttons.tsx index f5e2220c5e90..401c55ca90c8 100644 --- a/x-pack/plugins/session_view/public/components/process_tree_node/buttons.tsx +++ b/x-pack/plugins/session_view/public/components/process_tree_node/buttons.tsx @@ -86,8 +86,8 @@ export const AlertButton = ({ {alertsCount > 1 ? ALERTS : ALERT} {alertsCount > 1 && (alertsCount > MAX_ALERT_COUNT ? ` (${MAX_ALERT_COUNT}+)` : ` (${alertsCount})`)} - {alertIcons?.map((icon: string) => ( - + {alertIcons?.map((icon: string, index: number) => ( + ))} diff --git a/x-pack/plugins/session_view/public/test/index.tsx b/x-pack/plugins/session_view/public/test/index.tsx index 23f5fe8b25ce..876d0427e91a 100644 --- a/x-pack/plugins/session_view/public/test/index.tsx +++ b/x-pack/plugins/session_view/public/test/index.tsx @@ -116,7 +116,7 @@ export const createAppRootMockRenderer = (): AppContextTestRender => { }, }); - const AppWrapper: React.FC<{ children: React.ReactElement }> = ({ children }) => ( + const AppWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( {children} diff --git a/x-pack/plugins/spaces/public/management/components/solution_view/solution_view.tsx b/x-pack/plugins/spaces/public/management/components/solution_view/solution_view.tsx index 2d4818ff0b93..701490be4c4c 100644 --- a/x-pack/plugins/spaces/public/management/components/solution_view/solution_view.tsx +++ b/x-pack/plugins/spaces/public/management/components/solution_view/solution_view.tsx @@ -79,7 +79,7 @@ const getOptions = ({ size }: EuiThemeComputed): Array - + {i18n.translate( 'xpack.spaces.management.manageSpacePage.solutionViewSelect.classicOptionLabel', { defaultMessage: 'Classic' } @@ -151,6 +151,16 @@ export const SolutionView: FunctionComponent = ({ defaultMessage: 'Solution view', })} fullWidth + helpText={ + + {showClassicDefaultViewCallout ? ( + + ) : null} + + } {...validator.validateSolutionView(space, isEditing)} > = ({ {showClassicDefaultViewCallout && ( <> - - - - { return render( - - _), - navigateToUrl: jest.fn(), - license: licenseMock, - isRoleManagementEnabled: true, - capabilities: { - navLinks: {}, - management: {}, - catalogue: {}, - spaces: { manage: true }, - }, - dispatch: dispatchMock, - state: { - roles: new Map(), - fetchRolesError: false, - }, - invokeClient: spacesClientsInvocatorMock, - }} - > - + + _), + navigateToUrl: jest.fn(), + license: licenseMock, + isRoleManagementEnabled: true, + capabilities: { + navLinks: {}, + management: {}, + catalogue: {}, + spaces: { manage: true }, + }, + dispatch: dispatchMock, + state: { + roles: new Map(), + fetchRolesError: false, + }, + invokeClient: spacesClientsInvocatorMock, }} - /> - - + > + + + + ); }; diff --git a/x-pack/plugins/spaces/public/nav_control/components/spaces_menu.tsx b/x-pack/plugins/spaces/public/nav_control/components/spaces_menu.tsx index 29d360fe91f3..3a055fabd2cb 100644 --- a/x-pack/plugins/spaces/public/nav_control/components/spaces_menu.tsx +++ b/x-pack/plugins/spaces/public/nav_control/components/spaces_menu.tsx @@ -117,7 +117,7 @@ class SpacesMenuUI extends Component { {search || i18n.translate('xpack.spaces.navControl.spacesMenu.selectSpacesTitle', { - defaultMessage: 'Your spaces', + defaultMessage: 'Spaces', })} {list} diff --git a/x-pack/plugins/spaces/public/nav_control/nav_control_popover.tsx b/x-pack/plugins/spaces/public/nav_control/nav_control_popover.tsx index cd08ff87e1a5..31a721e4b02e 100644 --- a/x-pack/plugins/spaces/public/nav_control/nav_control_popover.tsx +++ b/x-pack/plugins/spaces/public/nav_control/nav_control_popover.tsx @@ -97,7 +97,7 @@ class NavControlPopoverUI extends Component { const isTourOpen = Boolean(activeSpace) && this.state.showTour && !this.state.showSpaceSelector; let element: React.ReactNode; - if (this.state.loading || this.state.spaces.length < 2) { + if (this.state.loading) { element = ( { onChange(updatedSpaceIds); }} legend={buttonGroupLegend} - color="success" + color="text" isFullWidth={true} isDisabled={!canShareToAllSpaces || isGlobalControlChangeProhibited} /> diff --git a/x-pack/plugins/spaces/server/capabilities/capabilities_switcher.test.ts b/x-pack/plugins/spaces/server/capabilities/capabilities_switcher.test.ts index 688f8297271a..33c32acfef01 100644 --- a/x-pack/plugins/spaces/server/capabilities/capabilities_switcher.test.ts +++ b/x-pack/plugins/spaces/server/capabilities/capabilities_switcher.test.ts @@ -392,14 +392,12 @@ describe('capabilitiesSwitcher', () => { { space.solution = 'oblt'; - // It should disable enterpriseSearch and securitySolution features - // which correspond to feature_1 and feature_3 + // It should disable securitySolution features + // which corresponds to feature_3 const result = await switcher(request, capabilities, false); const expectedCapabilities = buildCapabilities(); - expectedCapabilities.feature_1.bar = false; - expectedCapabilities.feature_1.foo = false; expectedCapabilities.feature_3.bar = false; expectedCapabilities.feature_3.foo = false; diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index 24a94b43029e..9da144facf4f 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -49,9 +49,21 @@ describe.skip('onPostAuthInterceptor', () => { */ function initKbnServer(router: IRouter, basePath: IBasePath) { - router.get({ path: '/api/np_test/foo', validate: false }, (context, req, h) => { - return h.ok({ body: { path: req.url.pathname, basePath: basePath.get(req) } }); - }); + router.get( + { + path: '/api/np_test/foo', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, + (context, req, h) => { + return h.ok({ body: { path: req.url.pathname, basePath: basePath.get(req) } }); + } + ); } async function request( diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts index bf3d0a57ccae..3a5ce95ec334 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts @@ -38,14 +38,32 @@ describe.skip('onRequestInterceptor', () => { function initKbnServer(router: IRouter, basePath: IBasePath) { router.get( - { path: '/np_foo', validate: false }, + { + path: '/np_foo', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, (context: unknown, req: KibanaRequest, h: KibanaResponseFactory) => { return h.ok({ body: { path: req.url.pathname, basePath: basePath.get(req) } }); } ); router.get( - { path: '/some/path/s/np_foo/bar', validate: false }, + { + path: '/some/path/s/np_foo/bar', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, + validate: false, + }, (context: unknown, req: KibanaRequest, h: KibanaResponseFactory) => { return h.ok({ body: { path: req.url.pathname, basePath: basePath.get(req) } }); } @@ -54,6 +72,12 @@ describe.skip('onRequestInterceptor', () => { router.get( { path: '/i/love/np_spaces', + security: { + authz: { + enabled: false, + reason: 'This route is opted out from authorization', + }, + }, validate: { query: schema.object({ queryParam: schema.string({ diff --git a/x-pack/plugins/spaces/server/lib/utils/space_solution_disabled_features.test.ts b/x-pack/plugins/spaces/server/lib/utils/space_solution_disabled_features.test.ts index 908a4ee2ced5..f19b4d585dc2 100644 --- a/x-pack/plugins/spaces/server/lib/utils/space_solution_disabled_features.test.ts +++ b/x-pack/plugins/spaces/server/lib/utils/space_solution_disabled_features.test.ts @@ -58,7 +58,7 @@ describe('#withSpaceSolutionDisabledFeatures', () => { }); describe('when the space solution is "oblt"', () => { - test('it removes the "search" and "security" features', () => { + test('it removes the "security" features', () => { const spaceDisabledFeatures: string[] = []; const spaceSolution = 'oblt'; @@ -68,7 +68,7 @@ describe('#withSpaceSolutionDisabledFeatures', () => { spaceSolution ); - expect(result).toEqual(['feature2', 'feature3']); + expect(result).toEqual(['feature3']); }); }); diff --git a/x-pack/plugins/spaces/server/lib/utils/space_solution_disabled_features.ts b/x-pack/plugins/spaces/server/lib/utils/space_solution_disabled_features.ts index 6d3064532553..2682daf3a1c5 100644 --- a/x-pack/plugins/spaces/server/lib/utils/space_solution_disabled_features.ts +++ b/x-pack/plugins/spaces/server/lib/utils/space_solution_disabled_features.ts @@ -62,7 +62,6 @@ export function withSpaceSolutionDisabledFeatures( ]).filter((featureId) => !enabledFeaturesPerSolution.es.includes(featureId)); } else if (spaceSolution === 'oblt') { disabledFeatureKeysFromSolution = getFeatureIdsForCategories(features, [ - 'enterpriseSearch', 'securitySolution', ]).filter((featureId) => !enabledFeaturesPerSolution.oblt.includes(featureId)); } else if (spaceSolution === 'security') { diff --git a/x-pack/plugins/spaces/server/routes/api/external/delete.ts b/x-pack/plugins/spaces/server/routes/api/external/delete.ts index 06bef75774aa..4908f1a747b7 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/delete.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/delete.ts @@ -31,6 +31,13 @@ export function initDeleteSpacesApi(deps: ExternalRouteDeps) { .addVersion( { version: API_VERSIONS.public.v1, + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the spaces service via a scoped spaces client', + }, + }, validate: { request: { params: schema.object({ diff --git a/x-pack/plugins/spaces/server/routes/api/external/disable_legacy_url_aliases.ts b/x-pack/plugins/spaces/server/routes/api/external/disable_legacy_url_aliases.ts index a1610bbfed97..2703e7c36f0c 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/disable_legacy_url_aliases.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/disable_legacy_url_aliases.ts @@ -18,6 +18,13 @@ export function initDisableLegacyUrlAliasesApi(deps: ExternalRouteDeps) { router.post( { path: '/api/spaces/_disable_legacy_url_aliases', + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the spaces service via a scoped spaces client', + }, + }, options: { access: isServerless ? 'internal' : 'public', summary: 'Disable legacy URL aliases', diff --git a/x-pack/plugins/spaces/server/routes/api/external/get.ts b/x-pack/plugins/spaces/server/routes/api/external/get.ts index b1ab2dc57577..3c9871e44490 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get.ts @@ -28,6 +28,13 @@ export function initGetSpaceApi(deps: ExternalRouteDeps) { .addVersion( { version: API_VERSIONS.public.v1, + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the spaces service via a scoped spaces client', + }, + }, validate: { request: { params: schema.object({ diff --git a/x-pack/plugins/spaces/server/routes/api/external/get_all.ts b/x-pack/plugins/spaces/server/routes/api/external/get_all.ts index 746735bb3736..f7a0c4592387 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get_all.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get_all.ts @@ -27,6 +27,13 @@ export function initGetAllSpacesApi(deps: ExternalRouteDeps) { .addVersion( { version: API_VERSIONS.public.v1, + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the spaces service via a scoped spaces client', + }, + }, validate: { request: { query: schema.object({ diff --git a/x-pack/plugins/spaces/server/routes/api/external/get_shareable_references.ts b/x-pack/plugins/spaces/server/routes/api/external/get_shareable_references.ts index f49070be66fe..98dab60cd9c9 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get_shareable_references.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get_shareable_references.ts @@ -17,6 +17,13 @@ export function initGetShareableReferencesApi(deps: ExternalRouteDeps) { router.post( { path: '/api/spaces/_get_shareable_references', + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the spaces service via a scoped spaces client', + }, + }, options: { access: isServerless ? 'internal' : 'public', summary: `Get shareable references`, diff --git a/x-pack/plugins/spaces/server/routes/api/external/post.ts b/x-pack/plugins/spaces/server/routes/api/external/post.ts index de1ec53aaee4..2ecd70828d57 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/post.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/post.ts @@ -30,6 +30,13 @@ export function initPostSpacesApi(deps: ExternalRouteDeps) { .addVersion( { version: API_VERSIONS.public.v1, + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the spaces service via a scoped spaces client', + }, + }, validate: { request: { body: getSpaceSchema(isServerless), diff --git a/x-pack/plugins/spaces/server/routes/api/external/put.ts b/x-pack/plugins/spaces/server/routes/api/external/put.ts index 740e81bac446..abdac1f0977d 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/put.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/put.ts @@ -29,6 +29,13 @@ export function initPutSpacesApi(deps: ExternalRouteDeps) { .addVersion( { version: API_VERSIONS.public.v1, + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the spaces service via a scoped spaces client', + }, + }, validate: { request: { params: schema.object({ diff --git a/x-pack/plugins/spaces/server/routes/api/external/update_objects_spaces.ts b/x-pack/plugins/spaces/server/routes/api/external/update_objects_spaces.ts index 9fb2a8626a84..fb9137a83434 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/update_objects_spaces.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/update_objects_spaces.ts @@ -40,6 +40,13 @@ export function initUpdateObjectsSpacesApi(deps: ExternalRouteDeps) { router.post( { path: '/api/spaces/_update_objects_spaces', + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the spaces service via a scoped spaces client', + }, + }, options: { access: isServerless ? 'internal' : 'public', summary: `Update saved objects in spaces`, diff --git a/x-pack/plugins/spaces/server/routes/api/internal/get_active_space.ts b/x-pack/plugins/spaces/server/routes/api/internal/get_active_space.ts index 2996e7dbc4ed..2480b0c003fe 100644 --- a/x-pack/plugins/spaces/server/routes/api/internal/get_active_space.ts +++ b/x-pack/plugins/spaces/server/routes/api/internal/get_active_space.ts @@ -15,6 +15,13 @@ export function initGetActiveSpaceApi(deps: InternalRouteDeps) { router.get( { path: '/internal/spaces/_active_space', + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the spaces service getActiveSpace API, which uses a scoped spaces client', + }, + }, validate: false, }, createLicensedRouteHandler(async (context, request, response) => { diff --git a/x-pack/plugins/spaces/server/routes/api/internal/set_solution_space.ts b/x-pack/plugins/spaces/server/routes/api/internal/set_solution_space.ts index 6732a8520946..cfe14705a4e2 100644 --- a/x-pack/plugins/spaces/server/routes/api/internal/set_solution_space.ts +++ b/x-pack/plugins/spaces/server/routes/api/internal/set_solution_space.ts @@ -37,6 +37,13 @@ export function initSetSolutionSpaceApi(deps: InternalRouteDeps) { router.put( { path: '/internal/spaces/space/{id}/solution', + security: { + authz: { + enabled: false, + reason: + 'This route delegates authorization to the spaces service via a scoped spaces client', + }, + }, options: { description: `Update solution for a space`, }, diff --git a/x-pack/plugins/stack_connectors/common/auth/constants.ts b/x-pack/plugins/stack_connectors/common/auth/constants.ts index bdd5b7352f92..ecf7637c956e 100644 --- a/x-pack/plugins/stack_connectors/common/auth/constants.ts +++ b/x-pack/plugins/stack_connectors/common/auth/constants.ts @@ -19,4 +19,5 @@ export enum WebhookMethods { PATCH = 'patch', POST = 'post', PUT = 'put', + GET = 'get', } diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/types.ts b/x-pack/plugins/stack_connectors/common/dynamic_config/types.ts similarity index 100% rename from x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/types.ts rename to x-pack/plugins/stack_connectors/common/dynamic_config/types.ts diff --git a/x-pack/plugins/stack_connectors/common/inference/types.ts b/x-pack/plugins/stack_connectors/common/inference/types.ts index 9dbd447cb457..b9561efe2429 100644 --- a/x-pack/plugins/stack_connectors/common/inference/types.ts +++ b/x-pack/plugins/stack_connectors/common/inference/types.ts @@ -19,6 +19,7 @@ import { TextEmbeddingParamsSchema, TextEmbeddingResponseSchema, } from './schema'; +import { ConfigProperties } from '../dynamic_config/types'; export type Config = TypeOf; export type Secrets = TypeOf; @@ -36,3 +37,17 @@ export type TextEmbeddingParams = TypeOf; export type TextEmbeddingResponse = TypeOf; export type StreamingResponse = TypeOf; + +export type FieldsConfiguration = Record; + +export interface InferenceTaskType { + task_type: string; + configuration: FieldsConfiguration; +} + +export interface InferenceProvider { + provider: string; + task_types: InferenceTaskType[]; + logo?: string; + configuration: FieldsConfiguration; +} diff --git a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/steps/get.tsx b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/steps/get.tsx index e8f233408a4c..5bf2689506ec 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/steps/get.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/steps/get.tsx @@ -6,14 +6,25 @@ */ import React, { FunctionComponent } from 'react'; +import { css } from '@emotion/react'; import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; -import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { + FIELD_TYPES, + UseField, + useFormData, +} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { Field } from '@kbn/es-ui-shared-plugin/static/forms/components'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; -import { MustacheTextFieldWrapper } from '@kbn/triggers-actions-ui-plugin/public'; -import { containsExternalId, containsExternalIdOrTitle } from '../validator'; +import { JsonFieldWrapper, MustacheTextFieldWrapper } from '@kbn/triggers-actions-ui-plugin/public'; +import { WebhookMethods } from '../../../../common/auth/constants'; +import { + containsExternalIdForGet, + containsExternalIdOrTitle, + requiredJsonForPost, +} from '../validator'; import { urlVars, urlVarsExt } from '../action_variables'; import * as i18n from '../translations'; + const { emptyField, urlField } = fieldValidators; interface Props { @@ -21,88 +32,157 @@ interface Props { readOnly: boolean; } -export const GetStep: FunctionComponent = ({ display, readOnly }) => ( - - -

    {i18n.STEP_3}

    - -

    {i18n.STEP_3_DESCRIPTION}

    -
    -
    - - - - - - = ({ display, readOnly }) => { + const [{ config }] = useFormData({ + watch: ['config.getIncidentMethod'], + }); + const { getIncidentMethod = WebhookMethods.GET } = config ?? {}; + + return ( + + +

    {i18n.STEP_3}

    + +

    {i18n.STEP_3_DESCRIPTION}

    +
    +
    + + + + ({ + text: verb.toUpperCase(), + value: verb, + })), + readOnly, + }, + }} + /> + + + + + + {getIncidentMethod === WebhookMethods.POST ? ( + + + + ) : null} + + - - - + + + - - -
    -); + }} + /> +
    +
    +
    + ); +}; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts index 0b007e07cfd9..8c44b6197ef9 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/translations.ts @@ -178,13 +178,24 @@ export const ADD_CASES_VARIABLE = i18n.translate( defaultMessage: 'Add variable', } ); - +export const GET_INCIDENT_METHOD = i18n.translate( + 'xpack.stackConnectors.components.casesWebhook.getIncidentMethodTextFieldLabel', + { + defaultMessage: 'Get case method', + } +); export const GET_INCIDENT_URL = i18n.translate( 'xpack.stackConnectors.components.casesWebhook.getIncidentUrlTextFieldLabel', { defaultMessage: 'Get case URL', } ); +export const GET_METHOD_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.casesWebhook.error.requiredGetMethodText', + { + defaultMessage: 'Get case method is required.', + } +); export const GET_INCIDENT_URL_HELP = i18n.translate( 'xpack.stackConnectors.components.casesWebhook.getIncidentUrlHelp', { @@ -206,6 +217,28 @@ export const GET_INCIDENT_TITLE_KEY_HELP = i18n.translate( } ); +export const GET_INCIDENT_JSON_HELP = i18n.translate( + 'xpack.stackConnectors.components.casesWebhook.getIncidentJsonHelp', + { + defaultMessage: + 'JSON object to get a case. Use the variable selector to add cases data to the payload.', + } +); + +export const GET_INCIDENT_JSON = i18n.translate( + 'xpack.stackConnectors.components.casesWebhook.getIncidentJsonTextFieldLabel', + { + defaultMessage: 'Get case object', + } +); + +export const GET_INCIDENT_REQUIRED = i18n.translate( + 'xpack.stackConnectors.components.casesWebhook.error.requiredGetIncidentText', + { + defaultMessage: 'Get case object is required and must be valid JSON.', + } +); + export const EXTERNAL_INCIDENT_VIEW_URL = i18n.translate( 'xpack.stackConnectors.components.casesWebhook.viewIncidentUrlTextFieldLabel', { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/validator.ts b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/validator.ts index d3d7f6dc8e61..d972c9bbd1f8 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/validator.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/validator.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { isEmpty } from 'lodash'; import { ERROR_CODE } from '@kbn/es-ui-shared-plugin/static/forms/helpers/field_validators/types'; import { ValidationError, @@ -12,6 +13,7 @@ import { } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { containsChars, isUrl } from '@kbn/es-ui-shared-plugin/static/validators/string'; import { templateActionVariable } from '@kbn/triggers-actions-ui-plugin/public'; +import { WebhookMethods } from '../../../common/auth/constants'; import * as i18n from './translations'; import { casesVars, commentVars, urlVars, urlVarsExt } from './action_variables'; @@ -42,17 +44,20 @@ export const containsTitleAndDesc = } }; -export const containsExternalId = - () => +export const containsExternalIdForGet = + (method?: string) => (...args: Parameters): ReturnType> => { const [{ value, path }] = args; const id = templateActionVariable( urlVars.find((actionVariable) => actionVariable.name === 'external.system.id')! ); - return containsChars(id)(value as string).doesContain - ? undefined - : missingVariableErrorMessage(path, [id]); + + return method === WebhookMethods.GET && + value !== null && + !containsChars(id)(value as string).doesContain + ? missingVariableErrorMessage(path, [id]) + : undefined; }; export const containsExternalIdOrTitle = @@ -77,6 +82,20 @@ export const containsExternalIdOrTitle = return error; }; +export const requiredJsonForPost = + (method?: string) => + (...args: Parameters): ReturnType> => { + const [{ value, path }] = args; + + const error = { + code: errorCode, + path, + message: i18n.GET_INCIDENT_REQUIRED, + }; + + return method === WebhookMethods.POST && (value === null || isEmpty(value)) ? error : undefined; + }; + export const containsCommentsOrEmpty = (message: string) => (...args: Parameters): ReturnType> => { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/webhook_connectors.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/webhook_connectors.test.tsx index 8df473fef2ae..713f2bd9e6f8 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/webhook_connectors.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/webhook_connectors.test.tsx @@ -42,6 +42,7 @@ const config = { headers: [{ key: 'content-type', value: 'text' }], viewIncidentUrl: 'https://coolsite.net/browse/{{{external.system.title}}}', getIncidentUrl: 'https://coolsite.net/rest/api/2/issue/{{{external.system.id}}}', + getIncidentMethod: 'get', updateIncidentJson: '{"fields":{"summary":{{{case.title}}},"description":{{{case.description}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}', updateIncidentMethod: 'put', @@ -536,5 +537,78 @@ describe('CasesWebhookActionConnectorFields renders', () => { ).toBeInTheDocument(); } ); + + it('validates get incident json required correctly', async () => { + const connector = { + ...actionConnector, + config: { + ...actionConnector.config, + getIncidentUrl: 'https://coolsite.net/rest/api/2/issue', + getIncidentMethod: 'post', + headers: [], + }, + }; + + render( + + {}} + /> + + ); + + await userEvent.click(await screen.findByTestId('form-test-provide-submit')); + await waitFor(() => expect(onSubmit).toHaveBeenCalledWith({ data: {}, isValid: false })); + expect(await screen.findByText(i18n.GET_INCIDENT_REQUIRED)).toBeInTheDocument(); + }); + + it('validation succeeds get incident url with post correctly', async () => { + const connector = { + ...actionConnector, + config: { + ...actionConnector.config, + getIncidentUrl: 'https://coolsite.net/rest/api/2/issue/{{{external.system.id}}}', + getIncidentMethod: 'post', + getIncidentJson: '{"id": {{{external.system.id}}} }', + headers: [], + }, + }; + + const { isPreconfigured, ...rest } = actionConnector; + const { headers, ...rest2 } = actionConnector.config; + + render( + + {}} + /> + + ); + + await userEvent.click(await screen.findByTestId('form-test-provide-submit')); + + await waitFor(() => + expect(onSubmit).toHaveBeenCalledWith({ + data: { + __internal__: { + hasCA: false, + hasHeaders: true, + }, + ...rest, + config: { + ...rest2, + getIncidentUrl: 'https://coolsite.net/rest/api/2/issue/{{{external.system.id}}}', + getIncidentMethod: 'post', + getIncidentJson: '{"id": {{{external.system.id}}} }', + }, + }, + isValid: true, + }) + ); + }); }); }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/webhook_connectors.tsx b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/webhook_connectors.tsx index 73e424901469..5aaf56fa8dd9 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/webhook_connectors.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/cases_webhook/webhook_connectors.tsx @@ -22,7 +22,7 @@ import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; import * as i18n from './translations'; import { AuthStep, CreateStep, GetStep, UpdateStep } from './steps'; -export const HTTP_VERBS = ['post', 'put', 'patch']; +export const HTTP_VERBS = ['post', 'put', 'patch', 'get']; const fields = { step1: [ 'config.hasAuth', @@ -38,7 +38,9 @@ const fields = { 'config.createIncidentResponseKey', ], step3: [ + 'config.getIncidentMethod', 'config.getIncidentUrl', + 'config.getIncidentJson', 'config.getIncidentResponseExternalTitleKey', 'config.viewIncidentUrl', ], diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/additional_options_fields.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/additional_options_fields.tsx index 8973f3124bc8..7a3b1abfd800 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/additional_options_fields.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/additional_options_fields.tsx @@ -32,10 +32,10 @@ import { import { FormattedMessage } from '@kbn/i18n-react'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; +import { ConfigEntryView } from '../../../common/dynamic_config/types'; import { ConnectorConfigurationFormItems } from '../lib/dynamic_config/connector_configuration_form_items'; import * as i18n from './translations'; import { DEFAULT_TASK_TYPE } from './constants'; -import { ConfigEntryView } from '../lib/dynamic_config/types'; import { Config } from './types'; import { TaskTypeOption } from './helpers'; @@ -52,7 +52,7 @@ interface AdditionalOptionsConnectorFieldsProps { isEdit: boolean; optionalProviderFormFields: ConfigEntryView[]; onSetProviderConfigEntry: (key: string, value: unknown) => Promise; - onTaskTypeOptionsSelect: (taskType: string, provider?: string) => Promise; + onTaskTypeOptionsSelect: (taskType: string, provider?: string) => void; selectedTaskType?: string; taskTypeFormFields: ConfigEntryView[]; taskTypeSchema: ConfigEntryView[]; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/connector.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/connector.test.tsx index 44632e8b0833..d445504011b5 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/connector.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/connector.test.tsx @@ -12,13 +12,10 @@ import { ConnectorFormTestProvider } from '../lib/test_utils'; import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { createStartServicesMock } from '@kbn/triggers-actions-ui-plugin/public/common/lib/kibana/kibana_react.mock'; -import { DisplayType, FieldType } from '../lib/dynamic_config/types'; import { useProviders } from './providers/get_providers'; -import { getTaskTypes } from './get_task_types'; -import { HttpSetup } from '@kbn/core-http-browser'; +import { DisplayType, FieldType } from '../../../common/dynamic_config/types'; jest.mock('./providers/get_providers'); -jest.mock('./get_task_types'); const mockUseKibanaReturnValue = createStartServicesMock(); jest.mock('@kbn/triggers-actions-ui-plugin/public/common/lib/kibana', () => ({ @@ -37,13 +34,32 @@ jest.mock('@faker-js/faker', () => ({ })); const mockProviders = useProviders as jest.Mock; -const mockTaskTypes = getTaskTypes as jest.Mock; const providersSchemas = [ { provider: 'openai', logo: '', // should be openai logo here, the hardcoded uses assets/images - taskTypes: ['completion', 'text_embedding'], + task_types: [ + { + task_type: 'completion', + configuration: { + user: { + display: DisplayType.TEXTBOX, + label: 'User', + order: 1, + required: false, + sensitive: false, + tooltip: 'Specifies the user issuing the request.', + type: FieldType.STRING, + validations: [], + value: '', + ui_restrictions: [], + default_value: null, + depends_on: [], + }, + }, + }, + ], configuration: { api_key: { display: DisplayType.TEXTBOX, @@ -106,7 +122,16 @@ const providersSchemas = [ { provider: 'googleaistudio', logo: '', // should be googleaistudio logo here, the hardcoded uses assets/images - taskTypes: ['completion', 'text_embedding'], + task_types: [ + { + task_type: 'completion', + configuration: {}, + }, + { + task_type: 'text_embedding', + configuration: {}, + }, + ], configuration: { api_key: { display: DisplayType.TEXTBOX, @@ -139,39 +164,6 @@ const providersSchemas = [ }, }, ]; -const taskTypesSchemas: Record = { - googleaistudio: [ - { - task_type: 'completion', - configuration: {}, - }, - { - task_type: 'text_embedding', - configuration: {}, - }, - ], - openai: [ - { - task_type: 'completion', - configuration: { - user: { - display: DisplayType.TEXTBOX, - label: 'User', - order: 1, - required: false, - sensitive: false, - tooltip: 'Specifies the user issuing the request.', - type: FieldType.STRING, - validations: [], - value: '', - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - ], -}; const openAiConnector = { actionTypeId: '.inference', @@ -222,9 +214,6 @@ describe('ConnectorFields renders', () => { isLoading: false, data: providersSchemas, }); - mockTaskTypes.mockImplementation( - (http: HttpSetup, provider: string) => taskTypesSchemas[provider] - ); }); test('openai provider fields are rendered', async () => { const { getAllByTestId } = render( diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/connector.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/connector.tsx index 35314dc06167..5f854384dbb5 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/connector.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/connector.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useState, useEffect, useCallback } from 'react'; +import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { EuiFormRow, EuiSpacer, @@ -31,12 +31,12 @@ import { import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; +import { ConfigEntryView } from '../../../common/dynamic_config/types'; +import { InferenceTaskType } from '../../../common/inference/types'; import { ServiceProviderKeys } from '../../../common/inference/constants'; import { ConnectorConfigurationFormItems } from '../lib/dynamic_config/connector_configuration_form_items'; -import { getTaskTypes } from './get_task_types'; import * as i18n from './translations'; import { DEFAULT_TASK_TYPE } from './constants'; -import { ConfigEntryView } from '../lib/dynamic_config/types'; import { SelectableProvider } from './providers/selectable'; import { Config, Secrets } from './types'; import { generateInferenceEndpointId, getTaskTypeOptions, TaskTypeOption } from './helpers'; @@ -116,13 +116,13 @@ const InferenceAPIConnectorFields: React.FunctionComponent { + (taskType: string, provider?: string) => { // Get task type settings - const currentTaskTypes = await getTaskTypes(http, provider ?? config?.provider); + const currentProvider = providers?.find((p) => p.provider === (provider ?? config?.provider)); + const currentTaskTypes = currentProvider?.task_types; const newTaskType = currentTaskTypes?.find((p) => p.task_type === taskType); setSelectedTaskType(taskType); - generateInferenceEndpointId(config, setFieldValue); // transform the schema const newTaskTypeSchema = Object.keys(newTaskType?.configuration ?? {}).map((k) => ({ @@ -150,19 +150,23 @@ const InferenceAPIConnectorFields: React.FunctionComponent { + (provider?: string) => { const newProvider = providers?.find((p) => p.provider === provider); // Update task types list available for the selected provider - const providerTaskTypes = newProvider?.taskTypes ?? []; + const providerTaskTypes = (newProvider?.task_types ?? []).map((t) => t.task_type); setTaskTypeOptions(getTaskTypeOptions(providerTaskTypes)); if (providerTaskTypes.length > 0) { - await onTaskTypeOptionsSelect(providerTaskTypes[0], provider); + onTaskTypeOptionsSelect(providerTaskTypes[0], provider); } // Update connector providerSchema @@ -203,9 +207,8 @@ const InferenceAPIConnectorFields: React.FunctionComponent { - const getTaskTypeSchema = async () => { - const currentTaskTypes = await getTaskTypes(http, config?.provider ?? ''); - const newTaskType = currentTaskTypes?.find((p) => p.task_type === config?.taskType); + const getTaskTypeSchema = (taskTypes: InferenceTaskType[]) => { + const newTaskType = taskTypes.find((p) => p.task_type === config?.taskType); // transform the schema const newTaskTypeSchema = Object.keys(newTaskType?.configuration ?? {}).map((k) => ({ @@ -228,7 +231,7 @@ const InferenceAPIConnectorFields: React.FunctionComponent + Object.keys(SERVICE_PROVIDERS).includes(config?.provider) + ? SERVICE_PROVIDERS[config?.provider as ServiceProviderKeys].icon + : undefined, + [config?.provider] + ); + + const providerName = useMemo( + () => + Object.keys(SERVICE_PROVIDERS).includes(config?.provider) + ? SERVICE_PROVIDERS[config?.provider as ServiceProviderKeys].name + : config?.provider, + [config?.provider] + ); + const providerSuperSelect = useCallback( (isInvalid: boolean) => ( jest.resetAllMocks()); - -describe.skip('getTaskTypes', () => { - test('should call get inference task types api', async () => { - const apiResponse = { - amazonbedrock: [ - { - task_type: 'completion', - configuration: { - max_new_tokens: { - display: DisplayType.NUMERIC, - label: 'Max new tokens', - order: 1, - required: false, - sensitive: false, - tooltip: 'Sets the maximum number for the output tokens to be generated.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - task_type: 'text_embedding', - configuration: {}, - }, - ], - }; - http.get.mockResolvedValueOnce(apiResponse); - - const result = await getTaskTypes(http, 'amazonbedrock'); - expect(result).toEqual(apiResponse); - }); -}); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/get_task_types.ts b/x-pack/plugins/stack_connectors/public/connector_types/inference/get_task_types.ts deleted file mode 100644 index a4fbbd6a6288..000000000000 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/get_task_types.ts +++ /dev/null @@ -1,606 +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 { HttpSetup } from '@kbn/core-http-browser'; -import { DisplayType, FieldType } from '../lib/dynamic_config/types'; -import { FieldsConfiguration } from './types'; - -export interface InferenceTaskType { - task_type: string; - configuration: FieldsConfiguration; -} - -// this http param is for the future migrating to real API -export const getTaskTypes = (http: HttpSetup, provider: string): Promise => { - const providersTaskTypes: Record = { - openai: [ - { - task_type: 'completion', - configuration: { - user: { - display: DisplayType.TEXTBOX, - label: 'User', - order: 1, - required: false, - sensitive: false, - tooltip: 'Specifies the user issuing the request.', - type: FieldType.STRING, - validations: [], - value: '', - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - task_type: 'text_embedding', - configuration: { - user: { - display: DisplayType.TEXTBOX, - label: 'User', - order: 1, - required: false, - sensitive: false, - tooltip: 'Specifies the user issuing the request.', - type: FieldType.STRING, - validations: [], - value: '', - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - ], - mistral: [ - { - task_type: 'text_embedding', - configuration: {}, - }, - ], - hugging_face: [ - { - task_type: 'text_embedding', - configuration: {}, - }, - ], - googlevertexai: [ - { - task_type: 'text_embedding', - configuration: { - auto_truncate: { - display: DisplayType.TOGGLE, - label: 'Auto truncate', - order: 1, - required: false, - sensitive: false, - tooltip: - 'Specifies if the API truncates inputs longer than the maximum token length automatically.', - type: FieldType.BOOLEAN, - validations: [], - value: false, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - task_type: 'rerank', - configuration: { - top_n: { - display: DisplayType.TOGGLE, - label: 'Top N', - order: 1, - required: false, - sensitive: false, - tooltip: 'Specifies the number of the top n documents, which should be returned.', - type: FieldType.BOOLEAN, - validations: [], - value: false, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - ], - googleaistudio: [ - { - task_type: 'completion', - configuration: {}, - }, - { - task_type: 'text_embedding', - configuration: {}, - }, - ], - elasticsearch: [ - { - task_type: 'rerank', - configuration: { - return_documents: { - display: DisplayType.TOGGLE, - label: 'Return documents', - options: [], - order: 1, - required: false, - sensitive: false, - tooltip: 'Returns the document instead of only the index.', - type: FieldType.BOOLEAN, - validations: [], - value: true, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - task_type: 'sparse_embedding', - configuration: {}, - }, - { - task_type: 'text_embedding', - configuration: {}, - }, - ], - cohere: [ - { - task_type: 'completion', - configuration: {}, - }, - { - task_type: 'text_embedding', - configuration: { - input_type: { - display: DisplayType.DROPDOWN, - label: 'Input type', - order: 1, - required: false, - sensitive: false, - tooltip: 'Specifies the type of input passed to the model.', - type: FieldType.STRING, - validations: [], - options: [ - { - label: 'classification', - value: 'classification', - }, - { - label: 'clusterning', - value: 'clusterning', - }, - { - label: 'ingest', - value: 'ingest', - }, - { - label: 'search', - value: 'search', - }, - ], - value: '', - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - truncate: { - display: DisplayType.DROPDOWN, - options: [ - { - label: 'NONE', - value: 'NONE', - }, - { - label: 'START', - value: 'START', - }, - { - label: 'END', - value: 'END', - }, - ], - label: 'Truncate', - order: 2, - required: false, - sensitive: false, - tooltip: 'Specifies how the API handles inputs longer than the maximum token length.', - type: FieldType.STRING, - validations: [], - value: '', - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - task_type: 'rerank', - configuration: { - return_documents: { - display: DisplayType.TOGGLE, - label: 'Return documents', - order: 1, - required: false, - sensitive: false, - tooltip: 'Specify whether to return doc text within the results.', - type: FieldType.BOOLEAN, - validations: [], - value: false, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - top_n: { - display: DisplayType.NUMERIC, - label: 'Top N', - order: 1, - required: false, - sensitive: false, - tooltip: - 'The number of most relevant documents to return, defaults to the number of the documents.', - type: FieldType.INTEGER, - validations: [], - value: false, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - ], - azureopenai: [ - { - task_type: 'completion', - configuration: { - user: { - display: DisplayType.TEXTBOX, - label: 'User', - order: 1, - required: false, - sensitive: false, - tooltip: 'Specifies the user issuing the request.', - type: FieldType.STRING, - validations: [], - value: '', - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - task_type: 'text_embedding', - configuration: { - user: { - display: DisplayType.TEXTBOX, - label: 'User', - order: 1, - required: false, - sensitive: false, - tooltip: 'Specifies the user issuing the request.', - type: FieldType.STRING, - validations: [], - value: '', - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - ], - azureaistudio: [ - { - task_type: 'completion', - configuration: { - user: { - display: DisplayType.TEXTBOX, - label: 'User', - order: 1, - required: false, - sensitive: false, - tooltip: 'Specifies the user issuing the request.', - type: FieldType.STRING, - validations: [], - value: '', - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - task_type: 'text_embedding', - configuration: { - do_sample: { - display: DisplayType.NUMERIC, - label: 'Do sample', - order: 1, - required: false, - sensitive: false, - tooltip: 'Instructs the inference process to perform sampling or not.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - max_new_tokens: { - display: DisplayType.NUMERIC, - label: 'Max new tokens', - order: 1, - required: false, - sensitive: false, - tooltip: 'Provides a hint for the maximum number of output tokens to be generated.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - temperature: { - display: DisplayType.NUMERIC, - label: 'Temperature', - order: 1, - required: false, - sensitive: false, - tooltip: 'A number in the range of 0.0 to 2.0 that specifies the sampling temperature.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - top_p: { - display: DisplayType.NUMERIC, - label: 'Top P', - order: 1, - required: false, - sensitive: false, - tooltip: - 'A number in the range of 0.0 to 2.0 that is an alternative value to temperature. Should not be used if temperature is specified.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - ], - amazonbedrock: [ - { - task_type: 'completion', - configuration: { - max_new_tokens: { - display: DisplayType.NUMERIC, - label: 'Max new tokens', - order: 1, - required: false, - sensitive: false, - tooltip: 'Sets the maximum number for the output tokens to be generated.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - temperature: { - display: DisplayType.NUMERIC, - label: 'Temperature', - order: 1, - required: false, - sensitive: false, - tooltip: - 'A number between 0.0 and 1.0 that controls the apparent creativity of the results.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - top_p: { - display: DisplayType.NUMERIC, - label: 'Top P', - order: 1, - required: false, - sensitive: false, - tooltip: - 'Alternative to temperature. A number in the range of 0.0 to 1.0, to eliminate low-probability tokens.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - top_k: { - display: DisplayType.NUMERIC, - label: 'Top K', - order: 1, - required: false, - sensitive: false, - tooltip: - 'Only available for anthropic, cohere, and mistral providers. Alternative to temperature.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - task_type: 'text_embedding', - configuration: {}, - }, - ], - anthropic: [ - { - task_type: 'completion', - configuration: { - max_tokens: { - display: DisplayType.NUMERIC, - label: 'Max tokens', - order: 1, - required: true, - sensitive: false, - tooltip: 'The maximum number of tokens to generate before stopping.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - temperature: { - display: DisplayType.TEXTBOX, - label: 'Temperature', - order: 2, - required: false, - sensitive: false, - tooltip: 'The amount of randomness injected into the response.', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - top_p: { - display: DisplayType.NUMERIC, - label: 'Top P', - order: 4, - required: false, - sensitive: false, - tooltip: 'Specifies to use Anthropic’s nucleus sampling.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - top_k: { - display: DisplayType.NUMERIC, - label: 'Top K', - order: 3, - required: false, - sensitive: false, - tooltip: 'Specifies to only sample from the top K options for each subsequent token.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - ], - 'alibabacloud-ai-search': [ - { - task_type: 'text_embedding', - configuration: { - input_type: { - display: DisplayType.DROPDOWN, - label: 'Input type', - order: 1, - required: false, - sensitive: false, - tooltip: 'Specifies the type of input passed to the model.', - type: FieldType.STRING, - validations: [], - options: [ - { - label: 'ingest', - value: 'ingest', - }, - { - label: 'search', - value: 'search', - }, - ], - value: '', - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - task_type: 'sparse_embedding', - configuration: { - input_type: { - display: DisplayType.DROPDOWN, - label: 'Input type', - order: 1, - required: false, - sensitive: false, - tooltip: 'Specifies the type of input passed to the model.', - type: FieldType.STRING, - validations: [], - options: [ - { - label: 'ingest', - value: 'ingest', - }, - { - label: 'search', - value: 'search', - }, - ], - value: '', - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - return_token: { - display: DisplayType.TOGGLE, - label: 'Return token', - options: [], - order: 1, - required: false, - sensitive: false, - tooltip: - 'If `true`, the token name will be returned in the response. Defaults to `false` which means only the token ID will be returned in the response.', - type: FieldType.BOOLEAN, - validations: [], - value: true, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - task_type: 'completion', - configuration: {}, - }, - { - task_type: 'rerank', - configuration: {}, - }, - ], - watsonxai: [ - { - task_type: 'text_embedding', - configuration: {}, - }, - ], - }; - return Promise.resolve(providersTaskTypes[provider]); -}; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/helpers.ts b/x-pack/plugins/stack_connectors/public/connector_types/inference/helpers.ts index 0e1e4cdaa41a..8638caa998ef 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/helpers.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/helpers.ts @@ -7,7 +7,7 @@ import { isEmpty } from 'lodash/fp'; import { ValidationFunc } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { ConfigEntryView } from '../lib/dynamic_config/types'; +import { ConfigEntryView } from '../../../common/dynamic_config/types'; import { Config } from './types'; import * as i18n from './translations'; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/hidden_fields.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/hidden_fields.tsx index 9b28d35aaaf3..f6df891b4b9c 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/hidden_fields.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/hidden_fields.tsx @@ -8,8 +8,8 @@ import React from 'react'; import { HiddenField } from '@kbn/es-ui-shared-plugin/static/forms/components'; import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; +import { ConfigEntryView } from '../../../common/dynamic_config/types'; import { getNonEmptyValidator } from './helpers'; -import { ConfigEntryView } from '../lib/dynamic_config/types'; export const getProviderSecretsHiddenField = ( providerSchema: ConfigEntryView[], diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/providers/get_providers.ts b/x-pack/plugins/stack_connectors/public/connector_types/inference/providers/get_providers.ts index 109266c1273f..badc0cb61030 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/providers/get_providers.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/providers/get_providers.ts @@ -9,1025 +9,11 @@ import type { HttpSetup } from '@kbn/core-http-browser'; import { i18n } from '@kbn/i18n'; import { useQuery } from '@tanstack/react-query'; import type { ToastsStart } from '@kbn/core-notifications-browser'; -import { DisplayType, FieldType } from '../../lib/dynamic_config/types'; -import { FieldsConfiguration } from '../types'; +import { INTERNAL_BASE_STACK_CONNECTORS_API_PATH } from '../../../../common'; +import { InferenceProvider } from '../../../../common/inference/types'; -export interface InferenceProvider { - provider: string; - taskTypes: string[]; - logo?: string; - configuration: FieldsConfiguration; -} - -export const getProviders = (http: HttpSetup): Promise => { - const providers = [ - { - provider: 'openai', - logo: '', // should be openai logo here, the hardcoded uses assets/images - taskTypes: ['completion', 'text_embedding'], - configuration: { - api_key: { - display: DisplayType.TEXTBOX, - label: 'API Key', - order: 3, - required: true, - sensitive: true, - tooltip: `The OpenAI API authentication key. For more details about generating OpenAI API keys, refer to the https://platform.openai.com/account/api-keys.`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - model_id: { - display: DisplayType.TEXTBOX, - label: 'Model ID', - order: 2, - required: true, - sensitive: false, - tooltip: 'The name of the model to use for the inference task.', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - organization_id: { - display: DisplayType.TEXTBOX, - label: 'Organization ID', - order: 4, - required: false, - sensitive: false, - tooltip: 'The unique identifier of your organization.', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - url: { - display: DisplayType.TEXTBOX, - label: 'URL', - order: 1, - required: true, - sensitive: false, - tooltip: - 'The OpenAI API endpoint URL. For more information on the URL, refer to the https://platform.openai.com/docs/api-reference.', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: 'https://api.openai.com/v1/chat/completions', - depends_on: [], - }, - 'rate_limit.requests_per_minute': { - display: DisplayType.NUMERIC, - label: 'Rate limit', - order: 5, - required: false, - sensitive: false, - tooltip: - 'Default number of requests allowed per minute. For text_embedding is 3000. For completion is 500.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - provider: 'googleaistudio', - logo: '', // should be googleaistudio logo here, the hardcoded uses assets/images - taskTypes: ['completion', 'text_embedding'], - configuration: { - api_key: { - display: DisplayType.TEXTBOX, - label: 'API Key', - order: 1, - required: true, - sensitive: true, - tooltip: `API Key for the provider you're connecting to`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - model_id: { - display: DisplayType.TEXTBOX, - label: 'Model ID', - order: 2, - required: true, - sensitive: false, - tooltip: `ID of the LLM you're using`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - 'rate_limit.requests_per_minute': { - display: DisplayType.NUMERIC, - label: 'Rate limit', - order: 5, - required: false, - sensitive: false, - tooltip: 'Minimize the number of rate limit errors.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - provider: 'amazonbedrock', - logo: '', // should be amazonbedrock logo here, the hardcoded uses assets/images - taskTypes: ['completion', 'text_embedding'], - configuration: { - access_key: { - display: DisplayType.TEXTBOX, - label: 'Access Key', - order: 1, - required: true, - sensitive: true, - tooltip: `A valid AWS access key that has permissions to use Amazon Bedrock.`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - secret_key: { - display: DisplayType.TEXTBOX, - label: 'Secret Key', - order: 2, - required: true, - sensitive: true, - tooltip: `A valid AWS secret key that is paired with the access_key.`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - provider: { - display: DisplayType.DROPDOWN, - label: 'Provider', - order: 3, - required: true, - options: [ - { - label: 'amazontitan', - value: 'amazontitan', - }, - { - label: 'anthropic', - value: 'anthropic', - }, - { - label: 'ai21labs', - value: 'ai21labs', - }, - { - label: 'cohere', - value: 'cohere', - }, - { - label: 'meta', - value: 'meta', - }, - { - label: 'mistral', - value: 'mistral', - }, - ], - sensitive: false, - tooltip: 'The model provider for your deployment.', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - model: { - display: DisplayType.TEXTBOX, - label: 'Model', - order: 4, - required: true, - sensitive: false, - tooltip: `The base model ID or an ARN to a custom model based on a foundational model.`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - region: { - display: DisplayType.TEXTBOX, - label: 'Region', - order: 5, - required: true, - sensitive: false, - tooltip: `The region that your model or ARN is deployed in.`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - 'rate_limit.requests_per_minute': { - display: DisplayType.NUMERIC, - label: 'Rate limit', - order: 6, - required: false, - sensitive: false, - tooltip: - 'By default, the amazonbedrock service sets the number of requests allowed per minute to 240.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - provider: 'googlevertexai', - logo: '', // should be googlevertexai logo here, the hardcoded uses assets/images - taskTypes: ['text_embedding', 'rerank'], - configuration: { - service_account_json: { - display: DisplayType.TEXTBOX, - label: 'Credentials JSON', - order: 1, - required: true, - sensitive: true, - tooltip: `API Key for the provider you're connecting to`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - model_id: { - display: DisplayType.TEXTBOX, - label: 'Model ID', - order: 2, - required: true, - sensitive: false, - tooltip: `ID of the LLM you're using`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - location: { - display: DisplayType.TEXTBOX, - label: 'GCP Region', - order: 2, - required: true, - sensitive: false, - tooltip: `Please provide the GCP region where the Vertex AI API(s) is enabled. For more information, refer to the {geminiVertexAIDocs}.`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - project_id: { - display: DisplayType.TEXTBOX, - label: 'GCP Project', - order: 3, - required: true, - sensitive: false, - tooltip: - 'The GCP Project ID which has Vertex AI API(s) enabled. For more information on the URL, refer to the {geminiVertexAIDocs}.', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - 'rate_limit.requests_per_minute': { - display: DisplayType.NUMERIC, - label: 'Rate limit', - order: 5, - required: false, - sensitive: false, - tooltip: 'Minimize the number of rate limit errors.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - provider: 'mistral', - logo: '', // should be misral logo here, the hardcoded uses assets/images - taskTypes: ['text_embedding'], - configuration: { - api_key: { - display: DisplayType.TEXTBOX, - label: 'API Key', - order: 1, - required: true, - sensitive: true, - tooltip: `API Key for the provider you're connecting to`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - model: { - display: DisplayType.TEXTBOX, - label: 'Model', - order: 2, - required: true, - sensitive: false, - tooltip: `Refer to the Mistral models documentation for the list of available text embedding models`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - 'rate_limit.requests_per_minute': { - display: DisplayType.NUMERIC, - label: 'Rate limit', - order: 4, - required: false, - sensitive: false, - tooltip: 'Minimize the number of rate limit errors.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: 240, - depends_on: [], - }, - max_input_tokens: { - display: DisplayType.NUMERIC, - label: 'Maximum input tokens', - order: 3, - required: false, - sensitive: false, - tooltip: 'Allows you to specify the maximum number of tokens per input.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - provider: 'hugging_face', - logo: '', // should be hugging_face logo here, the hardcoded uses assets/images - taskTypes: ['text_embedding'], - configuration: { - api_key: { - display: DisplayType.TEXTBOX, - label: 'API Key', - order: 2, - required: true, - sensitive: true, - tooltip: `API Key for the provider you're connecting to`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - url: { - display: DisplayType.TEXTBOX, - label: 'URL', - order: 1, - required: true, - sensitive: false, - tooltip: 'The URL endpoint to use for the requests.', - type: FieldType.STRING, - validations: [], - value: 'https://api.openai.com/v1/embeddings', - ui_restrictions: [], - default_value: 'https://api.openai.com/v1/embeddings', - depends_on: [], - }, - 'rate_limit.requests_per_minute': { - display: DisplayType.NUMERIC, - label: 'Rate limit', - order: 3, - required: false, - sensitive: false, - tooltip: 'Minimize the number of rate limit errors.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - provider: 'elasticsearch', - logo: '', // elasticsearch logo here - taskTypes: ['sparse_embedding', 'text_embedding', 'rerank'], - configuration: { - model_id: { - display: DisplayType.DROPDOWN, - label: 'Model ID', - order: 1, - required: true, - sensitive: false, - tooltip: `The name of the model to use for the inference task.`, - type: FieldType.STRING, - validations: [], - options: [ - { - label: '.elser_model_1', - value: '.elser_model_1', - }, - { - label: '.elser_model_2', - value: '.elser_model_2', - }, - { - label: '.elser_model_2_linux-x86_64', - value: '.elser_model_2_linux-x86_64', - }, - { - label: '.multilingual-e5-small', - value: '.multilingual-e5-small', - }, - { - label: '.multilingual-e5-small_linux-x86_64', - value: '.multilingual-e5-small_linux-x86_64', - }, - ], - value: null, - ui_restrictions: [], - default_value: '.multilingual-e5-small', - depends_on: [], - }, - num_allocations: { - display: DisplayType.NUMERIC, - label: 'Number allocations', - order: 2, - required: true, - sensitive: false, - tooltip: - 'The total number of allocations this model is assigned across machine learning nodes.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: 1, - depends_on: [], - }, - num_threads: { - display: DisplayType.NUMERIC, - label: 'Number threads', - order: 3, - required: true, - sensitive: false, - tooltip: 'Sets the number of threads used by each model allocation during inference.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: 2, - depends_on: [], - }, - }, - }, - { - provider: 'cohere', - logo: '', // should be cohere logo here, the hardcoded uses assets/images - taskTypes: ['completion', 'text_embedding', 'rerank'], - configuration: { - api_key: { - display: DisplayType.TEXTBOX, - label: 'API Key', - order: 1, - required: true, - sensitive: true, - tooltip: `API Key for the provider you're connecting to`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - 'rate_limit.requests_per_minute': { - display: DisplayType.NUMERIC, - label: 'Rate limit', - order: 5, - required: false, - sensitive: false, - tooltip: 'Minimize the number of rate limit errors.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - provider: 'azureopenai', - logo: '', // should be azureopenai logo here, the hardcoded uses assets/images - taskTypes: ['completion', 'text_embedding'], - configuration: { - api_key: { - display: DisplayType.TEXTBOX, - label: 'API Key', - order: 1, - required: false, - sensitive: true, - tooltip: `You must provide either an API key or an Entra ID.`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - entra_id: { - display: DisplayType.TEXTBOX, - label: 'Entra ID', - order: 2, - required: false, - sensitive: true, - tooltip: `You must provide either an API key or an Entra ID.`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - resource_name: { - display: DisplayType.TEXTBOX, - label: 'Resource Name', - order: 3, - required: true, - sensitive: false, - tooltip: `The name of your Azure OpenAI resource`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - api_version: { - display: DisplayType.TEXTBOX, - label: 'API version', - order: 4, - required: true, - sensitive: false, - tooltip: 'The Azure API version ID to use.', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - deployment_id: { - display: DisplayType.TEXTBOX, - label: 'Deployment ID', - order: 5, - required: true, - sensitive: false, - tooltip: 'The deployment name of your deployed models.', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - 'rate_limit.requests_per_minute': { - display: DisplayType.NUMERIC, - label: 'Rate limit', - order: 5, - required: false, - sensitive: false, - tooltip: - 'The azureopenai service sets a default number of requests allowed per minute depending on the task type.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - provider: 'azureaistudio', - logo: '', // should be azureaistudio logo here, the hardcoded uses assets/images - taskTypes: ['completion', 'text_embedding'], - configuration: { - api_key: { - display: DisplayType.TEXTBOX, - label: 'API Key', - order: 1, - required: true, - sensitive: true, - tooltip: `API Key for the provider you're connecting to`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - target: { - display: DisplayType.TEXTBOX, - label: 'Target', - order: 2, - required: true, - sensitive: false, - tooltip: `The target URL of your Azure AI Studio model deployment.`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - endpoint_type: { - display: DisplayType.DROPDOWN, - label: 'Endpoint type', - order: 3, - required: true, - sensitive: false, - tooltip: 'Specifies the type of endpoint that is used in your model deployment.', - type: FieldType.STRING, - options: [ - { - label: 'token', - value: 'token', - }, - { - label: 'realtime', - value: 'realtime', - }, - ], - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - provider: { - display: DisplayType.DROPDOWN, - label: 'Provider', - order: 3, - required: true, - options: [ - { - label: 'cohere', - value: 'cohere', - }, - { - label: 'meta', - value: 'meta', - }, - { - label: 'microsoft_phi', - value: 'microsoft_phi', - }, - { - label: 'mistral', - value: 'mistral', - }, - { - label: 'openai', - value: 'openai', - }, - { - label: 'databricks', - value: 'databricks', - }, - ], - sensitive: false, - tooltip: 'The model provider for your deployment.', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - 'rate_limit.requests_per_minute': { - display: DisplayType.NUMERIC, - label: 'Rate limit', - order: 5, - required: false, - sensitive: false, - tooltip: 'Minimize the number of rate limit errors.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - provider: 'anthropic', - logo: '', // should be anthropic logo here, the hardcoded uses assets/images - taskTypes: ['completion'], - configuration: { - api_key: { - display: DisplayType.TEXTBOX, - label: 'API Key', - order: 1, - required: true, - sensitive: true, - tooltip: `API Key for the provider you're connecting to`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - model_id: { - display: DisplayType.TEXTBOX, - label: 'Model ID', - order: 2, - required: true, - sensitive: false, - tooltip: `The name of the model to use for the inference task.`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - 'rate_limit.requests_per_minute': { - display: DisplayType.NUMERIC, - label: 'Rate limit', - order: 5, - required: false, - sensitive: false, - tooltip: - 'By default, the anthropic service sets the number of requests allowed per minute to 50.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - provider: 'watsonxai', - logo: '', // should be anthropic logo here, the hardcoded uses assets/images - taskTypes: ['text_embedding'], - configuration: { - api_version: { - display: DisplayType.TEXTBOX, - label: 'API version', - order: 1, - required: true, - sensitive: false, - tooltip: 'The IBM Watsonx API version ID to use.', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - project_id: { - display: DisplayType.TEXTBOX, - label: 'Project ID', - order: 2, - required: true, - sensitive: false, - tooltip: '', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - model_id: { - display: DisplayType.TEXTBOX, - label: 'Model ID', - order: 3, - required: true, - sensitive: false, - tooltip: `The name of the model to use for the inference task.`, - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - url: { - display: DisplayType.TEXTBOX, - label: 'URL', - order: 4, - required: true, - sensitive: false, - tooltip: '', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - max_input_tokens: { - display: DisplayType.NUMERIC, - label: 'Maximum input tokens', - order: 5, - required: false, - sensitive: false, - tooltip: 'Allows you to specify the maximum number of tokens per input.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - { - provider: 'alibabacloud-ai-search', - logo: '', // should be anthropic logo here, the hardcoded uses assets/images - taskTypes: ['completion', 'sparse_embedding', 'text_embedding', 'rerank'], - configuration: { - api_key: { - display: DisplayType.TEXTBOX, - label: 'API Key', - order: 1, - required: true, - sensitive: true, - tooltip: 'A valid API key for the AlibabaCloud AI Search API.', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - service_id: { - display: DisplayType.DROPDOWN, - label: 'Project ID', - order: 2, - required: true, - sensitive: false, - tooltip: 'The name of the model service to use for the {infer} task.', - type: FieldType.STRING, - options: [ - { - label: 'ops-text-embedding-001', - value: 'ops-text-embedding-001', - }, - { - label: 'ops-text-embedding-zh-001', - value: 'ops-text-embedding-zh-001', - }, - { - label: 'ops-text-embedding-en-001', - value: 'ops-text-embedding-en-001', - }, - { - label: 'ops-text-embedding-002', - value: 'ops-text-embedding-002', - }, - { - label: 'ops-text-sparse-embedding-001', - value: 'ops-text-sparse-embedding-001', - }, - { - label: 'ops-bge-reranker-larger', - value: 'ops-bge-reranker-larger', - }, - ], - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - host: { - display: DisplayType.TEXTBOX, - label: 'Host', - order: 3, - required: true, - sensitive: false, - tooltip: - 'The name of the host address used for the {infer} task. You can find the host address at https://opensearch.console.aliyun.com/cn-shanghai/rag/api-key[ the API keys section] of the documentation.', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - http_schema: { - display: DisplayType.DROPDOWN, - label: 'HTTP Schema', - order: 4, - required: true, - sensitive: false, - tooltip: '', - type: FieldType.STRING, - options: [ - { - label: 'https', - value: 'https', - }, - { - label: 'http', - value: 'http', - }, - ], - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - workspace: { - display: DisplayType.TEXTBOX, - label: 'Workspace', - order: 5, - required: true, - sensitive: false, - tooltip: 'The name of the workspace used for the {infer} task.', - type: FieldType.STRING, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - 'rate_limit.requests_per_minute': { - display: DisplayType.NUMERIC, - label: 'Rate limit', - order: 6, - required: false, - sensitive: false, - tooltip: 'Minimize the number of rate limit errors.', - type: FieldType.INTEGER, - validations: [], - value: null, - ui_restrictions: [], - default_value: null, - depends_on: [], - }, - }, - }, - ] as InferenceProvider[]; - return Promise.resolve( - providers.sort((a, b) => (a.provider > b.provider ? 1 : b.provider > a.provider ? -1 : 0)) - ); +export const getProviders = async (http: HttpSetup): Promise => { + return await http.get(`${INTERNAL_BASE_STACK_CONNECTORS_API_PATH}/_inference/_services`); }; export const useProviders = (http: HttpSetup, toasts: ToastsStart) => { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/providers/render_service_provider/service_provider.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/providers/render_service_provider/service_provider.tsx index 5d2c99ffd92c..5eb8518a5ea1 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/providers/render_service_provider/service_provider.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/providers/render_service_provider/service_provider.tsx @@ -26,7 +26,7 @@ interface ServiceProviderProps { searchValue?: string; } -type ProviderSolution = 'Observability' | 'Security' | 'Search'; +export type ProviderSolution = 'Observability' | 'Security' | 'Search'; interface ServiceProviderRecord { icon: string; @@ -107,9 +107,7 @@ export const ServiceProviderIcon: React.FC = ({ providerKe return provider ? ( - ) : ( - {providerKey} - ); + ) : null; }; export const ServiceProviderName: React.FC = ({ diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/providers/selectable/index.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/providers/selectable/index.tsx index d4527e9c7b9a..fc31c9dd6c4f 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/providers/selectable/index.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/providers/selectable/index.tsx @@ -11,6 +11,7 @@ import React, { memo, useCallback, useMemo, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { ServiceProviderKeys } from '../../../../../common/inference/constants'; import { + ProviderSolution, SERVICE_PROVIDERS, ServiceProviderIcon, ServiceProviderName, @@ -47,7 +48,20 @@ const SelectableProviderComponent: React.FC = ({ const renderProviderOption = useCallback>( (option, searchValue) => { - const provider = SERVICE_PROVIDERS[option.label as ServiceProviderKeys]; + const provider = Object.keys(SERVICE_PROVIDERS).includes(option.label) + ? SERVICE_PROVIDERS[option.label as ServiceProviderKeys] + : undefined; + + const supportedBySolutions = (provider && + provider.solutions.map((solution) => ( + + {solution} + + ))) ?? ( + + {'Search' as ProviderSolution} + + ); return ( @@ -65,12 +79,7 @@ const SelectableProviderComponent: React.FC = ({ - {provider && - provider.solutions.map((solution) => ( - - {solution} - - ))} + {supportedBySolutions} diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/types.ts b/x-pack/plugins/stack_connectors/public/connector_types/inference/types.ts index 150292894b64..1bd55793bc46 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/types.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/types.ts @@ -14,7 +14,6 @@ import { SparseEmbeddingParams, TextEmbeddingParams, } from '../../../common/inference/types'; -import { ConfigProperties } from '../lib/dynamic_config/types'; export type InferenceActionParams = | { subAction: SUB_ACTION.COMPLETION; subActionParams: ChatCompleteParams } @@ -22,8 +21,6 @@ export type InferenceActionParams = | { subAction: SUB_ACTION.SPARSE_EMBEDDING; subActionParams: SparseEmbeddingParams } | { subAction: SUB_ACTION.TEXT_EMBEDDING; subActionParams: TextEmbeddingParams }; -export type FieldsConfiguration = Record; - export interface Config { taskType: string; taskTypeConfig?: Record; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_field.tsx b/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_field.tsx index 79ae552a9528..5560c831c4a6 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_field.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_field.tsx @@ -25,12 +25,12 @@ import { } from '@elastic/eui'; import { isEmpty } from 'lodash/fp'; +import { ConfigEntryView, DisplayType } from '../../../../common/dynamic_config/types'; import { ensureBooleanType, ensureCorrectTyping, ensureStringType, } from './connector_configuration_utils'; -import { ConfigEntryView, DisplayType } from './types'; interface ConnectorConfigurationFieldProps { configEntry: ConfigEntryView; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_form_items.tsx b/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_form_items.tsx index 3190ac80275f..a7063d81719a 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_form_items.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_form_items.tsx @@ -18,7 +18,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ConfigEntryView, DisplayType } from './types'; +import { ConfigEntryView, DisplayType } from '../../../../common/dynamic_config/types'; import { ConnectorConfigurationField } from './connector_configuration_field'; interface ConnectorConfigurationFormItemsProps { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_utils.ts b/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_utils.ts index 182327a180a6..cce5bc15fa56 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_utils.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/dynamic_config/connector_configuration_utils.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ConfigProperties, FieldType } from './types'; +import { ConfigProperties, FieldType } from '../../../../common/dynamic_config/types'; export type ConnectorConfigEntry = ConfigProperties & { key: string }; diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/test_utils.tsx b/x-pack/plugins/stack_connectors/public/connector_types/lib/test_utils.tsx index 29e0a8dd55b4..d1b9d1f0e340 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/test_utils.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/test_utils.tsx @@ -107,7 +107,7 @@ export interface AppMockRenderer { export const createAppMockRenderer = (): AppMockRenderer => { const services = createStartServicesMock(); - const AppWrapper: React.FC<{ children: React.ReactElement }> = ({ children }) => ( + const AppWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => ( {children} diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/schema.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/schema.ts index 00b4fdc60a3a..25b0d66e885b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/schema.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/schema.ts @@ -21,7 +21,14 @@ export const ExternalIncidentServiceConfiguration = { ), createIncidentJson: schema.string(), // stringified object createIncidentResponseKey: schema.string(), + getIncidentMethod: schema.oneOf( + [schema.literal(WebhookMethods.GET), schema.literal(WebhookMethods.POST)], + { + defaultValue: WebhookMethods.GET, + } + ), getIncidentUrl: schema.string(), + getIncidentJson: schema.nullable(schema.string()), getIncidentResponseExternalTitleKey: schema.string(), viewIncidentUrl: schema.string(), updateIncidentUrl: schema.string(), diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts index a44b34bf88fc..aaeca30be920 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts @@ -47,6 +47,8 @@ const config: CasesWebhookPublicConfigurationType = { headers: { ['content-type']: 'application/json', foo: 'bar' }, viewIncidentUrl: 'https://coolsite.net/browse/{{{external.system.title}}}', getIncidentUrl: 'https://coolsite.net/issue/{{{external.system.id}}}', + getIncidentMethod: WebhookMethods.GET, + getIncidentJson: null, updateIncidentJson: '{"fields":{"title":{{{case.title}}},"description":{{{case.description}}},"tags":{{{case.tags}}},"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}', updateIncidentMethod: WebhookMethods.PUT, @@ -239,6 +241,7 @@ describe('Cases webhook service', () => { configurationUtilities, sslOverrides: defaultSSLOverrides, connectorUsageCollector: expect.any(ConnectorUsageCollector), + method: WebhookMethods.GET, }); }); @@ -282,6 +285,7 @@ describe('Cases webhook service', () => { "trace": [MockFunction], "warn": [MockFunction], }, + "method": "get", "sslOverrides": Object { "cert": Object { "data": Array [ @@ -440,6 +444,271 @@ describe('Cases webhook service', () => { '[Action][Webhook - Case Management]: Unable to get case with id 1. Error: Response is missing the expected field: key' ); }); + + it('it returns the incident correctly with POST', async () => { + const postService: ExternalService = createExternalService( + actionId, + { + config: { + ...config, + getIncidentMethod: WebhookMethods.POST, + getIncidentJson: '{"id": {{{external.system.id}}} }', + getIncidentUrl: 'https://coolsite.net/issue', + }, + secrets, + }, + logger, + configurationUtilities, + connectorUsageCollector + ); + + requestMock.mockImplementation(() => createAxiosResponse(axiosRes)); + const res = await postService.getIncident('1'); + expect(res).toEqual({ + id: '1', + title: 'CK-1', + }); + }); + + it('it should call request with correct arguments using POST', async () => { + const postService: ExternalService = createExternalService( + actionId, + { + config: { + ...config, + getIncidentMethod: WebhookMethods.POST, + getIncidentJson: '{"id": {{{external.system.id}}} }', + getIncidentUrl: 'https://coolsite.net/issue', + }, + secrets, + }, + logger, + configurationUtilities, + connectorUsageCollector + ); + + requestMock.mockImplementation(() => createAxiosResponse(axiosRes)); + + await postService.getIncident('1'); + expect(requestMock).toHaveBeenCalledWith({ + axios, + url: 'https://coolsite.net/issue', + logger, + configurationUtilities, + sslOverrides: defaultSSLOverrides, + connectorUsageCollector: expect.any(ConnectorUsageCollector), + method: WebhookMethods.POST, + data: '{"id": "1" }', + }); + }); + + it('it should call request with correct arguments when authType=SSL using POST', async () => { + const postSslService = createExternalService( + actionId, + { + config: { + ...sslConfig, + getIncidentMethod: WebhookMethods.POST, + getIncidentJson: '{"id": {{{external.system.id}}} }', + getIncidentUrl: 'https://coolsite.net/issue', + }, + secrets: sslSecrets, + }, + logger, + configurationUtilities, + connectorUsageCollector + ); + + requestMock.mockImplementation(() => createAxiosResponse(axiosRes)); + + await postSslService.getIncident('1'); + + // irrelevant snapshot content + delete requestMock.mock.calls[0][0].configurationUtilities; + expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "axios": [Function], + "connectorUsageCollector": ConnectorUsageCollector { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "usage": Object { + "requestBodyBytes": 0, + }, + }, + "data": "{\\"id\\": \\"1\\" }", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "method": "post", + "sslOverrides": Object { + "cert": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 67, + 69, + 82, + 84, + 73, + 70, + 73, + 67, + 65, + 84, + 69, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "key": Object { + "data": Array [ + 10, + 45, + 45, + 45, + 45, + 45, + 66, + 69, + 71, + 73, + 78, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + 45, + 45, + 45, + 45, + 45, + 69, + 78, + 68, + 32, + 80, + 82, + 73, + 86, + 65, + 84, + 69, + 32, + 75, + 69, + 89, + 45, + 45, + 45, + 45, + 45, + 10, + ], + "type": "Buffer", + }, + "passphrase": "foobar", + }, + "url": "https://coolsite.net/issue", + } + `); + }); + + it('it should throw if the request payload is not a valid JSON for POST', async () => { + const newService = createExternalService( + actionId, + { + config: { + ...config, + getIncidentMethod: WebhookMethods.POST, + getIncidentJson: '{"id": }', + getIncidentUrl: 'https://coolsite.net/issue', + }, + secrets, + }, + logger, + configurationUtilities, + connectorUsageCollector + ); + + await expect(newService.getIncident('1')).rejects.toThrow( + '[Action][Webhook - Case Management]: Unable to get case with id 1. Error: JSON Error: Get case JSON body must be valid JSON. ' + ); + }); }); describe('createIncident', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts index 170c63a1d4e5..9f14f494c942 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts @@ -14,6 +14,7 @@ import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/action import { combineHeadersWithBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { buildConnectorAuth, validateConnectorAuthConfiguration } from '../../../common/auth/utils'; +import { WebhookMethods } from '../../../common/auth/constants'; import { validateAndNormalizeUrl, validateJson } from './validators'; import { createServiceError, @@ -52,6 +53,8 @@ export const createExternalService = ( createIncidentUrl: createIncidentUrlConfig, getIncidentResponseExternalTitleKey, getIncidentUrl, + getIncidentMethod, + getIncidentJson, hasAuth, authType, headers, @@ -113,10 +116,28 @@ export const createExternalService = ( configurationUtilities, 'Get case URL' ); + + const json = + getIncidentMethod === WebhookMethods.POST && getIncidentJson + ? renderMustacheStringNoEscape(getIncidentJson, { + external: { + system: { + id: JSON.stringify(id), + }, + }, + }) + : null; + + if (json !== null) { + validateJson(json, 'Get case JSON body'); + } + const res = await request({ axios: axiosInstance, url: normalizedUrl, + method: getIncidentMethod, logger, + ...(getIncidentMethod === WebhookMethods.POST ? { data: json } : {}), configurationUtilities, sslOverrides, connectorUsageCollector, @@ -128,6 +149,7 @@ export const createExternalService = ( }); const title = getObjectValueByKeyAsString(res.data, getIncidentResponseExternalTitleKey)!; + return { id, title }; } catch (error) { throw createServiceError(error, `Unable to get case with id ${id}`); @@ -157,6 +179,7 @@ export const createExternalService = ( ); validateJson(json, 'Create case JSON body'); + const res: AxiosResponse = await request({ axios: axiosInstance, url: normalizedUrl, @@ -175,6 +198,7 @@ export const createExternalService = ( requiredAttributesToBeInTheResponse: [createIncidentResponseKey], }); const externalId = getObjectValueByKeyAsString(data, createIncidentResponseKey)!; + const insertedIncident = await getIncident(externalId); logger.debug(`response from webhook action "${actionId}": [HTTP ${status}] ${statusText}`); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts index 5e98bdc96c0e..0001d7cf1328 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts @@ -36,67 +36,14 @@ const configurationUtilities = actionsConfigMock.create(); const issueTypesResponse = createAxiosResponse({ data: { - projects: [ + issueTypes: [ { - issuetypes: [ - { - id: '10006', - name: 'Task', - }, - { - id: '10007', - name: 'Bug', - }, - ], + id: '10006', + name: 'Task', }, - ], - }, -}); - -const fieldsResponse = createAxiosResponse({ - data: { - projects: [ { - issuetypes: [ - { - id: '10006', - name: 'Task', - fields: { - summary: { required: true, schema: { type: 'string' }, fieldId: 'summary' }, - priority: { - required: false, - schema: { type: 'string' }, - fieldId: 'priority', - allowedValues: [ - { - name: 'Highest', - id: '1', - }, - { - name: 'High', - id: '2', - }, - { - name: 'Medium', - id: '3', - }, - { - name: 'Low', - id: '4', - }, - { - name: 'Lowest', - id: '5', - }, - ], - defaultValue: { - name: 'Medium', - id: '3', - }, - }, - }, - }, - ], + id: '10007', + name: 'Bug', }, ], }, @@ -110,30 +57,6 @@ const issueResponse = { const issuesResponse = [issueResponse]; -const mockNewAPI = () => - requestMock.mockImplementationOnce(() => - createAxiosResponse({ - data: { - capabilities: { - 'list-project-issuetypes': - 'https://coolsite.net/rest/capabilities/list-project-issuetypes', - 'list-issuetype-fields': 'https://coolsite.net/rest/capabilities/list-issuetype-fields', - }, - }, - }) - ); - -const mockOldAPI = () => - requestMock.mockImplementationOnce(() => - createAxiosResponse({ - data: { - capabilities: { - navigation: 'https://coolsite.net/rest/capabilities/navigation', - }, - }, - }) - ); - describe('Jira service', () => { let service: ExternalService; let connectorUsageCollector: ConnectorUsageCollector; @@ -347,23 +270,6 @@ describe('Jira service', () => { }); test('it creates the incident correctly without issue type', async () => { - /* The response from Jira when creating an issue contains only the key and the id. - The function makes the following calls when creating an issue: - 1. Get issueTypes to set a default ONLY when incident.issueType is missing - 2. Create the issue. - 3. Get the created issue with all the necessary fields. - */ - // getIssueType mocks - requestMock.mockImplementationOnce(() => - createAxiosResponse({ - data: { - capabilities: { - navigation: 'https://coolsite.net/rest/capabilities/navigation', - }, - }, - }) - ); - // getIssueType mocks requestMock.mockImplementationOnce(() => issueTypesResponse); @@ -419,16 +325,6 @@ describe('Jira service', () => { }); test('removes newline characters and trialing spaces from summary', async () => { - requestMock.mockImplementationOnce(() => - createAxiosResponse({ - data: { - capabilities: { - navigation: 'https://coolsite.net/rest/capabilities/navigation', - }, - }, - }) - ); - // getIssueType mocks requestMock.mockImplementationOnce(() => issueTypesResponse); @@ -800,28 +696,47 @@ describe('Jira service', () => { }); }); - describe('getCapabilities', () => { - test('it should return the capabilities', async () => { - mockOldAPI(); - const res = await service.getCapabilities(); - expect(res).toEqual({ - capabilities: { - navigation: 'https://coolsite.net/rest/capabilities/navigation', + describe('getIssueTypes', () => { + test('it should return the issue types', async () => { + requestMock.mockImplementationOnce(() => + createAxiosResponse({ + data: { + issueTypes: issueTypesResponse.data.issueTypes, + }, + }) + ); + + const res = await service.getIssueTypes(); + + expect(res).toEqual([ + { + id: '10006', + name: 'Task', }, - }); + { + id: '10007', + name: 'Bug', + }, + ]); }); test('it should call request with correct arguments', async () => { - mockOldAPI(); + requestMock.mockImplementationOnce(() => + createAxiosResponse({ + data: { + issueTypes: issueTypesResponse.data.issueTypes, + }, + }) + ); - await service.getCapabilities(); + await service.getIssueTypes(); - expect(requestMock).toHaveBeenCalledWith({ + expect(requestMock).toHaveBeenLastCalledWith({ axios, logger, method: 'get', configurationUtilities, - url: 'https://coolsite.net/rest/capabilities', + url: 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes', connectorUsageCollector, }); }); @@ -829,25 +744,12 @@ describe('Jira service', () => { test('it should throw an error', async () => { requestMock.mockImplementation(() => { const error: ResponseError = new Error('An error has occurred'); - error.response = { data: { errors: { capabilities: 'Could not get capabilities' } } }; - throw error; - }); - - await expect(service.getCapabilities()).rejects.toThrow( - '[Action][Jira]: Unable to get capabilities. Error: An error has occurred. Reason: Could not get capabilities' - ); - }); - - test('it should return unknown if the error is a string', async () => { - requestMock.mockImplementation(() => { - const error = new Error('An error has occurred'); - // @ts-ignore - error.response = { data: 'Unauthorized' }; + error.response = { data: { errors: { issuetypes: 'Could not get issue types' } } }; throw error; }); - await expect(service.getCapabilities()).rejects.toThrow( - '[Action][Jira]: Unable to get capabilities. Error: An error has occurred. Reason: unknown: errorResponse.errors was null' + await expect(service.getIssueTypes()).rejects.toThrow( + '[Action][Jira]: Unable to get issue types. Error: An error has occurred. Reason: Could not get issue types' ); }); @@ -856,346 +758,178 @@ describe('Jira service', () => { createAxiosResponse({ data: { id: '1' }, headers: { ['content-type']: 'text/html' } }) ); - await expect(service.getCapabilities()).rejects.toThrow( - '[Action][Jira]: Unable to get capabilities. Error: Unsupported content type: text/html in GET https://example.com. Supported content types: application/json. Reason: unknown: errorResponse was null' - ); - }); - - test('it should throw if the required attributes are not there', async () => { - requestMock.mockImplementation(() => createAxiosResponse({ data: { notRequired: 'test' } })); - - await expect(service.getCapabilities()).rejects.toThrow( - '[Action][Jira]: Unable to get capabilities. Error: Response is missing at least one of the expected fields: capabilities. Reason: unknown: errorResponse was null' + await expect(service.getIssueTypes()).rejects.toThrow( + '[Action][Jira]: Unable to get issue types. Error: Unsupported content type: text/html in GET https://example.com. Supported content types: application/json. Reason: unknown: errorResponse was null' ); }); - }); - - describe('getIssueTypes', () => { - describe('Old API', () => { - test('it should return the issue types', async () => { - mockOldAPI(); - - requestMock.mockImplementationOnce(() => issueTypesResponse); - const res = await service.getIssueTypes(); - - expect(res).toEqual([ - { - id: '10006', - name: 'Task', - }, - { - id: '10007', - name: 'Bug', + test('it should work with data center response - issueTypes returned in data.values', async () => { + requestMock.mockImplementationOnce(() => + createAxiosResponse({ + data: { + values: issueTypesResponse.data.issueTypes, }, - ]); - }); - - test('it should call request with correct arguments', async () => { - mockOldAPI(); - - requestMock.mockImplementationOnce(() => issueTypesResponse); - - await service.getIssueTypes(); - - expect(requestMock).toHaveBeenLastCalledWith({ - axios, - logger, - method: 'get', - configurationUtilities, - url: 'https://coolsite.net/rest/api/2/issue/createmeta?projectKeys=CK&expand=projects.issuetypes.fields', - connectorUsageCollector, - }); - }); - - test('it should throw an error', async () => { - mockOldAPI(); - - requestMock.mockImplementation(() => { - const error: ResponseError = new Error('An error has occurred'); - error.response = { data: { errors: { issuetypes: 'Could not get issue types' } } }; - throw error; - }); - - await expect(service.getIssueTypes()).rejects.toThrow( - '[Action][Jira]: Unable to get issue types. Error: An error has occurred. Reason: Could not get issue types' - ); - }); - - test('it should throw if the request is not a JSON', async () => { - mockOldAPI(); + }) + ); - requestMock.mockImplementation(() => - createAxiosResponse({ data: { id: '1' }, headers: { ['content-type']: 'text/html' } }) - ); + await service.getIssueTypes(); - await expect(service.getIssueTypes()).rejects.toThrow( - '[Action][Jira]: Unable to get issue types. Error: Unsupported content type: text/html in GET https://example.com. Supported content types: application/json. Reason: unknown: errorResponse was null' - ); + expect(requestMock).toHaveBeenLastCalledWith({ + axios, + logger, + method: 'get', + configurationUtilities, + url: 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes', + connectorUsageCollector, }); }); - describe('New API', () => { - test('it should return the issue types', async () => { - mockNewAPI(); - - requestMock.mockImplementationOnce(() => - createAxiosResponse({ - data: { - values: issueTypesResponse.data.projects[0].issuetypes, - }, - }) - ); - - const res = await service.getIssueTypes(); + }); - expect(res).toEqual([ - { - id: '10006', - name: 'Task', - }, - { - id: '10007', - name: 'Bug', + describe('getFieldsByIssueType', () => { + test('it should return the fields', async () => { + requestMock.mockImplementationOnce(() => + createAxiosResponse({ + data: { + fields: [ + { required: true, schema: { type: 'string' }, fieldId: 'summary' }, + { + required: false, + schema: { type: 'string' }, + fieldId: 'priority', + allowedValues: [ + { + name: 'Medium', + id: '3', + }, + ], + defaultValue: { + name: 'Medium', + id: '3', + }, + }, + ], }, - ]); - }); - - test('it should call request with correct arguments', async () => { - mockNewAPI(); - - requestMock.mockImplementationOnce(() => - createAxiosResponse({ - data: { - values: issueTypesResponse.data.projects[0].issuetypes, - }, - }) - ); - - await service.getIssueTypes(); - - expect(requestMock).toHaveBeenLastCalledWith({ - axios, - logger, - method: 'get', - configurationUtilities, - url: 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes', - connectorUsageCollector, - }); - }); - - test('it should throw an error', async () => { - mockNewAPI(); - - requestMock.mockImplementation(() => { - const error: ResponseError = new Error('An error has occurred'); - error.response = { data: { errors: { issuetypes: 'Could not get issue types' } } }; - throw error; - }); - - await expect(service.getIssueTypes()).rejects.toThrow( - '[Action][Jira]: Unable to get issue types. Error: An error has occurred. Reason: Could not get issue types' - ); - }); - - test('it should throw if the request is not a JSON', async () => { - mockNewAPI(); + }) + ); - requestMock.mockImplementation(() => - createAxiosResponse({ data: { id: '1' }, headers: { ['content-type']: 'text/html' } }) - ); + const res = await service.getFieldsByIssueType('10006'); - await expect(service.getIssueTypes()).rejects.toThrow( - '[Action][Jira]: Unable to get issue types. Error: Unsupported content type: text/html in GET https://example.com. Supported content types: application/json. Reason: unknown: errorResponse was null' - ); + expect(res).toEqual({ + priority: { + required: false, + schema: { type: 'string' }, + allowedValues: [{ id: '3', name: 'Medium' }], + defaultValue: { id: '3', name: 'Medium' }, + }, + summary: { + required: true, + schema: { type: 'string' }, + allowedValues: [], + defaultValue: {}, + }, }); }); - }); - describe('getFieldsByIssueType', () => { - describe('Old API', () => { - test('it should return the fields', async () => { - mockOldAPI(); - - requestMock.mockImplementationOnce(() => fieldsResponse); - - const res = await service.getFieldsByIssueType('10006'); - - expect(res).toEqual({ - priority: { - required: false, - schema: { type: 'string' }, - allowedValues: [ - { id: '1', name: 'Highest' }, - { id: '2', name: 'High' }, - { id: '3', name: 'Medium' }, - { id: '4', name: 'Low' }, - { id: '5', name: 'Lowest' }, + test('it should call request with correct arguments', async () => { + requestMock.mockImplementationOnce(() => + createAxiosResponse({ + data: { + fields: [ + { required: true, schema: { type: 'string' }, fieldId: 'summary' }, + { + required: true, + schema: { type: 'string' }, + fieldId: 'priority', + allowedValues: [ + { + name: 'Medium', + id: '3', + }, + ], + defaultValue: { + name: 'Medium', + id: '3', + }, + }, ], - defaultValue: { id: '3', name: 'Medium' }, - }, - summary: { - required: true, - schema: { type: 'string' }, - allowedValues: [], - defaultValue: {}, }, - }); - }); - - test('it should call request with correct arguments', async () => { - mockOldAPI(); - - requestMock.mockImplementationOnce(() => fieldsResponse); + }) + ); - await service.getFieldsByIssueType('10006'); + await service.getFieldsByIssueType('10006'); - expect(requestMock).toHaveBeenLastCalledWith({ - axios, - logger, - method: 'get', - configurationUtilities, - url: 'https://coolsite.net/rest/api/2/issue/createmeta?projectKeys=CK&issuetypeIds=10006&expand=projects.issuetypes.fields', - connectorUsageCollector, - }); + expect(requestMock).toHaveBeenLastCalledWith({ + axios, + logger, + method: 'get', + configurationUtilities, + url: 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes/10006', }); + }); - test('it should throw an error', async () => { - mockOldAPI(); - - requestMock.mockImplementation(() => { - const error: ResponseError = new Error('An error has occurred'); - error.response = { data: { errors: { fields: 'Could not get fields' } } }; - throw error; - }); - - await expect(service.getFieldsByIssueType('10006')).rejects.toThrow( - '[Action][Jira]: Unable to get fields. Error: An error has occurred. Reason: Could not get fields' - ); + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + const error: ResponseError = new Error('An error has occurred'); + error.response = { data: { errors: { issuetypes: 'Could not get issue types' } } }; + throw error; }); - test('it should throw if the request is not a JSON', async () => { - mockOldAPI(); + await expect(service.getFieldsByIssueType('10006')).rejects.toThrowError( + '[Action][Jira]: Unable to get fields. Error: An error has occurred. Reason: Could not get issue types' + ); + }); - requestMock.mockImplementation(() => - createAxiosResponse({ data: { id: '1' }, headers: { ['content-type']: 'text/html' } }) - ); + test('it should throw if the request is not a JSON', async () => { + requestMock.mockImplementation(() => + createAxiosResponse({ data: { id: '1' }, headers: { ['content-type']: 'text/html' } }) + ); - await expect(service.getFieldsByIssueType('10006')).rejects.toThrow( - '[Action][Jira]: Unable to get fields. Error: Unsupported content type: text/html in GET https://example.com. Supported content types: application/json. Reason: unknown: errorResponse was null' - ); - }); + await expect(service.getFieldsByIssueType('10006')).rejects.toThrow( + '[Action][Jira]: Unable to get fields. Error: Unsupported content type: text/html in GET https://example.com. Supported content types: application/json. Reason: unknown: errorResponse was null' + ); }); - describe('New API', () => { - test('it should return the fields', async () => { - mockNewAPI(); - - requestMock.mockImplementationOnce(() => - createAxiosResponse({ - data: { - values: [ - { required: true, schema: { type: 'string' }, fieldId: 'summary' }, - { - required: false, - schema: { type: 'string' }, - fieldId: 'priority', - allowedValues: [ - { - name: 'Medium', - id: '3', - }, - ], - defaultValue: { + test('it should work with data center response - issueTypes returned in data.values', async () => { + requestMock.mockImplementationOnce(() => + createAxiosResponse({ + data: { + values: [ + { required: true, schema: { type: 'string' }, fieldId: 'summary' }, + { + required: false, + schema: { type: 'string' }, + fieldId: 'priority', + allowedValues: [ + { name: 'Medium', id: '3', }, + ], + defaultValue: { + name: 'Medium', + id: '3', }, - ], - }, - }) - ); - - const res = await service.getFieldsByIssueType('10006'); - - expect(res).toEqual({ - priority: { - required: false, - schema: { type: 'string' }, - allowedValues: [{ id: '3', name: 'Medium' }], - defaultValue: { id: '3', name: 'Medium' }, - }, - summary: { - required: true, - schema: { type: 'string' }, - allowedValues: [], - defaultValue: {}, + }, + ], }, - }); - }); - - test('it should call request with correct arguments', async () => { - mockNewAPI(); - - requestMock.mockImplementationOnce(() => - createAxiosResponse({ - data: { - values: [ - { required: true, schema: { type: 'string' }, fieldId: 'summary' }, - { - required: true, - schema: { type: 'string' }, - fieldId: 'priority', - allowedValues: [ - { - name: 'Medium', - id: '3', - }, - ], - defaultValue: { - name: 'Medium', - id: '3', - }, - }, - ], - }, - }) - ); - - await service.getFieldsByIssueType('10006'); - - expect(requestMock).toHaveBeenLastCalledWith({ - axios, - logger, - method: 'get', - configurationUtilities, - url: 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes/10006', - }); - }); - - test('it should throw an error', async () => { - mockNewAPI(); - - requestMock.mockImplementation(() => { - const error: ResponseError = new Error('An error has occurred'); - error.response = { data: { errors: { issuetypes: 'Could not get issue types' } } }; - throw error; - }); - - await expect(service.getFieldsByIssueType('10006')).rejects.toThrowError( - '[Action][Jira]: Unable to get fields. Error: An error has occurred. Reason: Could not get issue types' - ); - }); - - test('it should throw if the request is not a JSON', async () => { - mockNewAPI(); + }) + ); - requestMock.mockImplementation(() => - createAxiosResponse({ data: { id: '1' }, headers: { ['content-type']: 'text/html' } }) - ); + const res = await service.getFieldsByIssueType('10006'); - await expect(service.getFieldsByIssueType('10006')).rejects.toThrow( - '[Action][Jira]: Unable to get fields. Error: Unsupported content type: text/html in GET https://example.com. Supported content types: application/json. Reason: unknown: errorResponse was null' - ); + expect(res).toEqual({ + priority: { + required: false, + schema: { type: 'string' }, + allowedValues: [{ id: '3', name: 'Medium' }], + defaultValue: { id: '3', name: 'Medium' }, + }, + summary: { + required: true, + schema: { type: 'string' }, + allowedValues: [], + defaultValue: {}, + }, }); }); }); @@ -1403,50 +1137,14 @@ describe('Jira service', () => { .mockImplementationOnce(() => createAxiosResponse({ data: { - capabilities: { - 'list-project-issuetypes': - 'https://coolsite.net/rest/capabilities/list-project-issuetypes', - 'list-issuetype-fields': - 'https://coolsite.net/rest/capabilities/list-issuetype-fields', - }, - }, - }) - ) - .mockImplementationOnce(() => - createAxiosResponse({ - data: { - values: issueTypesResponse.data.projects[0].issuetypes, - }, - }) - ) - .mockImplementationOnce(() => - createAxiosResponse({ - data: { - capabilities: { - 'list-project-issuetypes': - 'https://coolsite.net/rest/capabilities/list-project-issuetypes', - 'list-issuetype-fields': - 'https://coolsite.net/rest/capabilities/list-issuetype-fields', - }, - }, - }) - ) - .mockImplementationOnce(() => - createAxiosResponse({ - data: { - capabilities: { - 'list-project-issuetypes': - 'https://coolsite.net/rest/capabilities/list-project-issuetypes', - 'list-issuetype-fields': - 'https://coolsite.net/rest/capabilities/list-issuetype-fields', - }, + issueTypes: issueTypesResponse.data.issueTypes, }, }) ) .mockImplementationOnce(() => createAxiosResponse({ data: { - values: [ + fields: [ { required: true, schema: { type: 'string' }, fieldId: 'summary' }, { required: true, schema: { type: 'string' }, fieldId: 'description' }, { @@ -1471,7 +1169,7 @@ describe('Jira service', () => { .mockImplementationOnce(() => createAxiosResponse({ data: { - values: [ + fields: [ { required: true, schema: { type: 'string' }, fieldId: 'summary' }, { required: true, schema: { type: 'string' }, fieldId: 'description' }, ], @@ -1488,10 +1186,7 @@ describe('Jira service', () => { callMocks(); await service.getFields(); const callUrls = [ - 'https://coolsite.net/rest/capabilities', 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes', - 'https://coolsite.net/rest/capabilities', - 'https://coolsite.net/rest/capabilities', 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes/10006', 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes/10007', ]; @@ -1525,7 +1220,7 @@ describe('Jira service', () => { throw error; }); await expect(service.getFields()).rejects.toThrow( - '[Action][Jira]: Unable to get capabilities. Error: An error has occurred. Reason: Required field' + '[Action][Jira]: Unable to get issue types. Error: An error has occurred. Reason: Required field' ); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts index 064667558b37..f8929ce67b68 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts @@ -39,12 +39,9 @@ import * as i18n from './translations'; const VERSION = '2'; const BASE_URL = `rest/api/${VERSION}`; -const CAPABILITIES_URL = `rest/capabilities`; const VIEW_INCIDENT_URL = `browse`; -const createMetaCapabilities = ['list-project-issuetypes', 'list-issuetype-fields']; - export const createExternalService = ( { config, secrets }: ExternalServiceCredentials, logger: Logger, @@ -60,10 +57,7 @@ export const createExternalService = ( const urlWithoutTrailingSlash = url.endsWith('/') ? url.slice(0, -1) : url; const incidentUrl = `${urlWithoutTrailingSlash}/${BASE_URL}/issue`; - const capabilitiesUrl = `${urlWithoutTrailingSlash}/${CAPABILITIES_URL}`; const commentUrl = `${incidentUrl}/{issueId}/comment`; - const getIssueTypesOldAPIURL = `${urlWithoutTrailingSlash}/${BASE_URL}/issue/createmeta?projectKeys=${projectKey}&expand=projects.issuetypes.fields`; - const getIssueTypeFieldsOldAPIURL = `${urlWithoutTrailingSlash}/${BASE_URL}/issue/createmeta?projectKeys=${projectKey}&issuetypeIds={issueTypeId}&expand=projects.issuetypes.fields`; const getIssueTypesUrl = `${urlWithoutTrailingSlash}/${BASE_URL}/issue/createmeta/${projectKey}/issuetypes`; const getIssueTypeFieldsUrl = `${urlWithoutTrailingSlash}/${BASE_URL}/issue/createmeta/${projectKey}/issuetypes/{issueTypeId}`; const searchUrl = `${urlWithoutTrailingSlash}/${BASE_URL}/search`; @@ -144,9 +138,6 @@ export const createExternalService = ( }, ''); }; - const hasSupportForNewAPI = (capabilities: { capabilities?: {} }) => - createMetaCapabilities.every((c) => Object.keys(capabilities?.capabilities ?? {}).includes(c)); - const normalizeIssueTypes = (issueTypes: Array<{ id: string; name: string }>) => issueTypes.map((type) => ({ id: type.id, name: type.name })); @@ -356,12 +347,12 @@ export const createExternalService = ( } }; - const getCapabilities = async () => { + const getIssueTypes = async () => { try { const res = await request({ axios: axiosInstance, method: 'get', - url: capabilitiesUrl, + url: getIssueTypesUrl, logger, configurationUtilities, connectorUsageCollector, @@ -369,59 +360,11 @@ export const createExternalService = ( throwIfResponseIsNotValid({ res, - requiredAttributesToBeInTheResponse: ['capabilities'], }); - return { ...res.data }; - } catch (error) { - throw new Error( - getErrorMessage( - i18n.NAME, - `Unable to get capabilities. Error: ${error.message}. Reason: ${createErrorMessage( - error.response?.data - )}` - ) - ); - } - }; - - const getIssueTypes = async () => { - const capabilitiesResponse = await getCapabilities(); - const supportsNewAPI = hasSupportForNewAPI(capabilitiesResponse); - try { - if (!supportsNewAPI) { - const res = await request({ - axios: axiosInstance, - method: 'get', - url: getIssueTypesOldAPIURL, - logger, - configurationUtilities, - connectorUsageCollector, - }); - - throwIfResponseIsNotValid({ - res, - }); - - const issueTypes = res.data.projects[0]?.issuetypes ?? []; - return normalizeIssueTypes(issueTypes); - } else { - const res = await request({ - axios: axiosInstance, - method: 'get', - url: getIssueTypesUrl, - logger, - configurationUtilities, - connectorUsageCollector, - }); - - throwIfResponseIsNotValid({ - res, - }); - - const issueTypes = res.data.values; - return normalizeIssueTypes(issueTypes); - } + // Cloud returns issueTypes and Data Center returns values + const { issueTypes, values } = res.data; + return normalizeIssueTypes(issueTypes || values); } catch (error) { throw new Error( getErrorMessage( @@ -435,47 +378,29 @@ export const createExternalService = ( }; const getFieldsByIssueType = async (issueTypeId: string) => { - const capabilitiesResponse = await getCapabilities(); - const supportsNewAPI = hasSupportForNewAPI(capabilitiesResponse); try { - if (!supportsNewAPI) { - const res = await request({ - axios: axiosInstance, - method: 'get', - url: createGetIssueTypeFieldsUrl(getIssueTypeFieldsOldAPIURL, issueTypeId), - logger, - configurationUtilities, - connectorUsageCollector, - }); - - throwIfResponseIsNotValid({ - res, - }); - - const fields = res.data.projects[0]?.issuetypes[0]?.fields || {}; - return normalizeFields(fields); - } else { - const res = await request({ - axios: axiosInstance, - method: 'get', - url: createGetIssueTypeFieldsUrl(getIssueTypeFieldsUrl, issueTypeId), - logger, - configurationUtilities, - }); - - throwIfResponseIsNotValid({ - res, - }); - - const fields = res.data.values.reduce( - (acc: { [x: string]: {} }, value: { fieldId: string }) => ({ - ...acc, - [value.fieldId]: { ...value }, - }), - {} - ); - return normalizeFields(fields); - } + const res = await request({ + axios: axiosInstance, + method: 'get', + url: createGetIssueTypeFieldsUrl(getIssueTypeFieldsUrl, issueTypeId), + logger, + configurationUtilities, + }); + + throwIfResponseIsNotValid({ + res, + }); + + // Cloud returns fields and Data Center returns values + const { fields: rawFields, values } = res.data; + const fields = (rawFields || values).reduce( + (acc: { [x: string]: {} }, value: { fieldId: string }) => ({ + ...acc, + [value.fieldId]: { ...value }, + }), + {} + ); + return normalizeFields(fields); } catch (error) { throw new Error( getErrorMessage( @@ -580,7 +505,6 @@ export const createExternalService = ( createIncident, updateIncident, createComment, - getCapabilities, getIssueTypes, getFieldsByIssueType, getIssues, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/types.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/types.ts index c975e23b1b78..755726137e41 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/types.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/types.ts @@ -101,7 +101,6 @@ export interface ExternalService { createComment: (params: CreateCommentParams) => Promise; createIncident: (params: CreateIncidentParams) => Promise; getFields: () => Promise; - getCapabilities: () => Promise; getFieldsByIssueType: (issueTypeId: string) => Promise; getIncident: (id: string) => Promise; getIssue: (id: string) => Promise; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/create_gen_ai_dashboard.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/create_gen_ai_dashboard.ts index ee5a3471a2d3..d54ccec0656e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/create_gen_ai_dashboard.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/create_gen_ai_dashboard.ts @@ -4,9 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; -import { DashboardAttributes } from '@kbn/dashboard-plugin/common'; +import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; +import type { DashboardSavedObjectAttributes } from '@kbn/dashboard-plugin/server'; import { Logger } from '@kbn/logging'; import { getDashboard } from './gen_ai_dashboard'; @@ -30,7 +30,7 @@ export const initDashboard = async ({ error?: OutputError; }> => { try { - await savedObjectsClient.get('dashboard', dashboardId); + await savedObjectsClient.get('dashboard', dashboardId); return { success: true, }; @@ -50,7 +50,7 @@ export const initDashboard = async ({ } try { - await savedObjectsClient.create( + await savedObjectsClient.create( 'dashboard', getDashboard(genAIProvider, dashboardId).attributes, { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/gen_ai_dashboard.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/gen_ai_dashboard.ts index 5805dd7728cc..efe5fc0c0ca6 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/gen_ai_dashboard.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/gen_ai/gen_ai_dashboard.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { DashboardAttributes } from '@kbn/dashboard-plugin/common'; +import type { DashboardSavedObjectAttributes } from '@kbn/dashboard-plugin/server'; import { v4 as uuidv4 } from 'uuid'; import { SavedObject } from '@kbn/core-saved-objects-common/src/server_types'; import { OPENAI_TITLE, OPENAI_CONNECTOR_ID } from '../../../../common/openai/constants'; @@ -21,7 +21,7 @@ export const getDashboardTitle = (title: string) => `${title} Token Usage`; export const getDashboard = ( genAIProvider: 'OpenAI' | 'Bedrock' | 'Gemini' | 'Inference', dashboardId: string -): SavedObject => { +): SavedObject => { let attributes = { provider: OPENAI_TITLE, dashboardTitle: getDashboardTitle(OPENAI_TITLE), diff --git a/x-pack/plugins/stack_connectors/server/plugin.ts b/x-pack/plugins/stack_connectors/server/plugin.ts index aee84d963043..b20892938735 100644 --- a/x-pack/plugins/stack_connectors/server/plugin.ts +++ b/x-pack/plugins/stack_connectors/server/plugin.ts @@ -8,7 +8,11 @@ import { PluginInitializerContext, Plugin, CoreSetup, Logger } from '@kbn/core/server'; import { PluginSetupContract as ActionsPluginSetupContract } from '@kbn/actions-plugin/server'; import { registerConnectorTypes } from './connector_types'; -import { validSlackApiChannelsRoute, getWellKnownEmailServiceRoute } from './routes'; +import { + validSlackApiChannelsRoute, + getWellKnownEmailServiceRoute, + getInferenceServicesRoute, +} from './routes'; import { ExperimentalFeatures, parseExperimentalConfigValue, @@ -39,6 +43,7 @@ export class StackConnectorsPlugin implements Plugin { getWellKnownEmailServiceRoute(router); validSlackApiChannelsRoute(router, actions.getActionsConfigurationUtilities(), this.logger); + getInferenceServicesRoute(router); registerConnectorTypes({ actions, diff --git a/x-pack/plugins/stack_connectors/server/routes/get_inference_services.test.ts b/x-pack/plugins/stack_connectors/server/routes/get_inference_services.test.ts new file mode 100644 index 000000000000..50596028d80a --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/routes/get_inference_services.test.ts @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { httpServiceMock, httpServerMock } from '@kbn/core/server/mocks'; +import { coreMock } from '@kbn/core/server/mocks'; +import { getInferenceServicesRoute } from './get_inference_services'; +import { DisplayType, FieldType } from '../../common/dynamic_config/types'; + +describe('getInferenceServicesRoute', () => { + it('returns available service providers', async () => { + const router = httpServiceMock.createRouter(); + const core = coreMock.createRequestHandlerContext(); + + const mockResult = [ + { + provider: 'openai', + task_types: [ + { + task_type: 'completion', + configuration: { + user: { + display: DisplayType.TEXTBOX, + label: 'User', + order: 1, + required: false, + sensitive: false, + tooltip: 'Specifies the user issuing the request.', + type: FieldType.STRING, + validations: [], + value: '', + ui_restrictions: [], + default_value: null, + depends_on: [], + }, + }, + }, + ], + configuration: { + api_key: { + display: DisplayType.TEXTBOX, + label: 'API Key', + order: 3, + required: true, + sensitive: true, + tooltip: `The OpenAI API authentication key. For more details about generating OpenAI API keys, refer to the https://platform.openai.com/account/api-keys.`, + type: FieldType.STRING, + validations: [], + value: null, + ui_restrictions: [], + default_value: null, + depends_on: [], + }, + model_id: { + display: DisplayType.TEXTBOX, + label: 'Model ID', + order: 2, + required: true, + sensitive: false, + tooltip: 'The name of the model to use for the inference task.', + type: FieldType.STRING, + validations: [], + value: null, + ui_restrictions: [], + default_value: null, + depends_on: [], + }, + organization_id: { + display: DisplayType.TEXTBOX, + label: 'Organization ID', + order: 4, + required: false, + sensitive: false, + tooltip: 'The unique identifier of your organization.', + type: FieldType.STRING, + validations: [], + value: null, + ui_restrictions: [], + default_value: null, + depends_on: [], + }, + url: { + display: DisplayType.TEXTBOX, + label: 'URL', + order: 1, + required: true, + sensitive: false, + tooltip: + 'The OpenAI API endpoint URL. For more information on the URL, refer to the https://platform.openai.com/docs/api-reference.', + type: FieldType.STRING, + validations: [], + value: null, + ui_restrictions: [], + default_value: 'https://api.openai.com/v1/chat/completions', + depends_on: [], + }, + 'rate_limit.requests_per_minute': { + display: DisplayType.NUMERIC, + label: 'Rate limit', + order: 5, + required: false, + sensitive: false, + tooltip: + 'Default number of requests allowed per minute. For text_embedding is 3000. For completion is 500.', + type: FieldType.INTEGER, + validations: [], + value: null, + ui_restrictions: [], + default_value: null, + depends_on: [], + }, + }, + }, + ]; + core.elasticsearch.client.asInternalUser.transport.request.mockResolvedValue(mockResult); + + getInferenceServicesRoute(router); + + const [config, handler] = router.get.mock.calls[0]; + expect(config.path).toMatchInlineSnapshot(`"/internal/stack_connectors/_inference/_services"`); + + const mockResponse = httpServerMock.createResponseFactory(); + const mockRequest = httpServerMock.createKibanaRequest(); + await handler({ core }, mockRequest, mockResponse); + + expect(mockResponse.ok).toHaveBeenCalledWith({ + body: mockResult, + }); + }); +}); diff --git a/x-pack/plugins/stack_connectors/server/routes/get_inference_services.ts b/x-pack/plugins/stack_connectors/server/routes/get_inference_services.ts new file mode 100644 index 000000000000..139607283426 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/routes/get_inference_services.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + IRouter, + RequestHandlerContext, + KibanaRequest, + IKibanaResponse, + KibanaResponseFactory, +} from '@kbn/core/server'; +import { InferenceProvider } from '../../common/inference/types'; +import { INTERNAL_BASE_STACK_CONNECTORS_API_PATH } from '../../common'; + +export const getInferenceServicesRoute = (router: IRouter) => { + router.get( + { + path: `${INTERNAL_BASE_STACK_CONNECTORS_API_PATH}/_inference/_services`, + options: { + access: 'internal', + }, + validate: false, + }, + handler + ); + + async function handler( + ctx: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise { + const esClient = (await ctx.core).elasticsearch.client.asInternalUser; + + const response = await esClient.transport.request<{ + endpoints: InferenceProvider[]; + }>({ + method: 'GET', + path: `/_inference/_services`, + }); + + return res.ok({ + body: response, + }); + } +}; diff --git a/x-pack/plugins/stack_connectors/server/routes/index.ts b/x-pack/plugins/stack_connectors/server/routes/index.ts index cd9857b2168e..e64995e1a50e 100644 --- a/x-pack/plugins/stack_connectors/server/routes/index.ts +++ b/x-pack/plugins/stack_connectors/server/routes/index.ts @@ -7,3 +7,4 @@ export { getWellKnownEmailServiceRoute } from './get_well_known_email_service'; export { validSlackApiChannelsRoute } from './valid_slack_api_channels'; +export { getInferenceServicesRoute } from './get_inference_services'; diff --git a/x-pack/plugins/task_manager/server/integration_tests/task_manager_capacity_based_claiming.test.ts b/x-pack/plugins/task_manager/server/integration_tests/task_manager_capacity_based_claiming.test.ts index b042655cfc26..d74dc1228336 100644 --- a/x-pack/plugins/task_manager/server/integration_tests/task_manager_capacity_based_claiming.test.ts +++ b/x-pack/plugins/task_manager/server/integration_tests/task_manager_capacity_based_claiming.test.ts @@ -94,7 +94,8 @@ jest.mock('../queries/task_claiming', () => { const taskManagerStartSpy = jest.spyOn(TaskManagerPlugin.prototype, 'start'); -describe('capacity based claiming', () => { +// FLAKY: https://github.com/elastic/kibana/issues/191117 +describe.skip('capacity based claiming', () => { const taskIdsToRemove: string[] = []; let esServer: TestElasticsearchUtils; let kibanaServer: TestKibanaUtils; diff --git a/x-pack/plugins/task_manager/server/plugin.ts b/x-pack/plugins/task_manager/server/plugin.ts index 45960195be21..cd820d1e7078 100644 --- a/x-pack/plugins/task_manager/server/plugin.ts +++ b/x-pack/plugins/task_manager/server/plugin.ts @@ -29,7 +29,7 @@ import { TaskManagerConfig } from './config'; import { createInitialMiddleware, addMiddlewareToChain, Middleware } from './lib/middleware'; import { removeIfExists } from './lib/remove_if_exists'; import { setupSavedObjects, BACKGROUND_TASK_NODE_SO_NAME, TASK_SO_NAME } from './saved_objects'; -import { TaskDefinitionRegistry, TaskTypeDictionary, REMOVED_TYPES } from './task_type_dictionary'; +import { TaskDefinitionRegistry, TaskTypeDictionary } from './task_type_dictionary'; import { AggregationOpts, FetchResult, SearchOpts, TaskStore } from './task_store'; import { createManagedConfiguration } from './lib/create_managed_configuration'; import { TaskScheduling } from './task_scheduling'; @@ -45,6 +45,10 @@ import { metricsStream, Metrics } from './metrics'; import { TaskManagerMetricsCollector } from './metrics/task_metrics_collector'; import { TaskPartitioner } from './lib/task_partitioner'; import { getDefaultCapacity } from './lib/get_default_capacity'; +import { + registerMarkRemovedTasksAsUnrecognizedDefinition, + scheduleMarkRemovedTasksAsUnrecognizedDefinition, +} from './removed_tasks/mark_removed_tasks_as_unrecognized'; export interface TaskManagerSetupContract { /** @@ -221,6 +225,11 @@ export class TaskManagerPlugin } registerDeleteInactiveNodesTaskDefinition(this.logger, core.getStartServices, this.definitions); + registerMarkRemovedTasksAsUnrecognizedDefinition( + this.logger, + core.getStartServices, + this.definitions + ); if (this.config.unsafe.exclude_task_types.length) { this.logger.warn( @@ -332,7 +341,6 @@ export class TaskManagerPlugin this.taskPollingLifecycle = new TaskPollingLifecycle({ config: this.config!, definitions: this.definitions, - unusedTypes: REMOVED_TYPES, logger: this.logger, executionContext, taskStore, @@ -384,6 +392,7 @@ export class TaskManagerPlugin }); scheduleDeleteInactiveNodesTaskDefinition(this.logger, taskScheduling).catch(() => {}); + scheduleMarkRemovedTasksAsUnrecognizedDefinition(this.logger, taskScheduling).catch(() => {}); return { fetch: (opts: SearchOpts): Promise => taskStore.fetch(opts), diff --git a/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts b/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts index 1f244f7f4c8a..a408bd3f634d 100644 --- a/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts +++ b/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts @@ -106,7 +106,6 @@ describe('TaskPollingLifecycle', () => { }, taskStore: mockTaskStore, logger: taskManagerLogger, - unusedTypes: [], definitions: new TaskTypeDictionary(taskManagerLogger), middleware: createInitialMiddleware(), startingCapacity: 20, diff --git a/x-pack/plugins/task_manager/server/polling_lifecycle.ts b/x-pack/plugins/task_manager/server/polling_lifecycle.ts index 0b1710ae7fa2..fb6776fa34f2 100644 --- a/x-pack/plugins/task_manager/server/polling_lifecycle.ts +++ b/x-pack/plugins/task_manager/server/polling_lifecycle.ts @@ -55,7 +55,6 @@ export interface ITaskEventEmitter { export type TaskPollingLifecycleOpts = { logger: Logger; definitions: TaskTypeDictionary; - unusedTypes: string[]; taskStore: TaskStore; config: TaskManagerConfig; middleware: Middleware; @@ -115,7 +114,6 @@ export class TaskPollingLifecycle implements ITaskEventEmitter this.pool.availableCapacity(taskType), taskPartitioner, diff --git a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.test.ts b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.test.ts index 76df8b7ae558..fa1d1f749985 100644 --- a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.test.ts +++ b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.test.ts @@ -70,7 +70,6 @@ describe('mark_available_tasks_as_claimed', () => { fieldUpdates, claimableTaskTypes: definitions.getAllTypes(), skippedTaskTypes: [], - unusedTaskTypes: [], taskMaxAttempts: Array.from(definitions).reduce((accumulator, [type, { maxAttempts }]) => { return { ...accumulator, [type]: maxAttempts || defaultMaxAttempts }; }, {}), @@ -153,8 +152,6 @@ if (doc['task.runAt'].size()!=0) { ctx._source.task.status = "claiming"; ${Object.keys(fieldUpdates) .map((field) => `ctx._source.task.${field}=params.fieldUpdates.${field};`) .join(' ')} - } else if (params.unusedTaskTypes.contains(ctx._source.task.taskType)) { - ctx._source.task.status = "unrecognized"; } else { ctx.op = "noop"; }`, @@ -167,7 +164,6 @@ if (doc['task.runAt'].size()!=0) { }, claimableTaskTypes: ['sampleTask', 'otherTask'], skippedTaskTypes: [], - unusedTaskTypes: [], taskMaxAttempts: { sampleTask: 5, otherTask: 1, @@ -242,7 +238,6 @@ if (doc['task.runAt'].size()!=0) { fieldUpdates, claimableTaskTypes: ['foo', 'bar'], skippedTaskTypes: [], - unusedTaskTypes: [], taskMaxAttempts: { foo: 5, bar: 2, diff --git a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts index 4e138545aec2..ec99c6ad5bf8 100644 --- a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts +++ b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts @@ -202,7 +202,6 @@ export interface UpdateFieldsAndMarkAsFailedOpts { }; claimableTaskTypes: string[]; skippedTaskTypes: string[]; - unusedTaskTypes: string[]; taskMaxAttempts: { [field: string]: number }; } @@ -210,7 +209,6 @@ export const updateFieldsAndMarkAsFailed = ({ fieldUpdates, claimableTaskTypes, skippedTaskTypes, - unusedTaskTypes, taskMaxAttempts, }: UpdateFieldsAndMarkAsFailedOpts): ScriptClause => { const setScheduledAtScript = `if(ctx._source.task.retryAt != null && ZonedDateTime.parse(ctx._source.task.retryAt).toInstant().toEpochMilli() < params.now) { @@ -227,8 +225,6 @@ export const updateFieldsAndMarkAsFailed = ({ source: ` if (params.claimableTaskTypes.contains(ctx._source.task.taskType)) { ${setScheduledAtAndMarkAsClaimed} - } else if (params.unusedTaskTypes.contains(ctx._source.task.taskType)) { - ctx._source.task.status = "unrecognized"; } else { ctx.op = "noop"; }`, @@ -238,7 +234,6 @@ export const updateFieldsAndMarkAsFailed = ({ fieldUpdates, claimableTaskTypes, skippedTaskTypes, - unusedTaskTypes, taskMaxAttempts, }, }; diff --git a/x-pack/plugins/task_manager/server/queries/task_claiming.test.ts b/x-pack/plugins/task_manager/server/queries/task_claiming.test.ts index 437af8e007bd..629e3464399c 100644 --- a/x-pack/plugins/task_manager/server/queries/task_claiming.test.ts +++ b/x-pack/plugins/task_manager/server/queries/task_claiming.test.ts @@ -83,7 +83,6 @@ describe('TaskClaiming', () => { strategy: 'non-default', definitions, excludedTaskTypes: [], - unusedTypes: [], taskStore: taskStoreMock.create({ taskManagerId: '' }), maxAttempts: 2, getAvailableCapacity: () => 10, @@ -134,7 +133,6 @@ describe('TaskClaiming', () => { strategy: 'default', definitions, excludedTaskTypes: [], - unusedTypes: [], taskStore: taskStoreMock.create({ taskManagerId: '' }), maxAttempts: 2, getAvailableCapacity: () => 10, diff --git a/x-pack/plugins/task_manager/server/queries/task_claiming.ts b/x-pack/plugins/task_manager/server/queries/task_claiming.ts index c9bca3175540..1b1e41490362 100644 --- a/x-pack/plugins/task_manager/server/queries/task_claiming.ts +++ b/x-pack/plugins/task_manager/server/queries/task_claiming.ts @@ -34,7 +34,6 @@ export interface TaskClaimingOpts { logger: Logger; strategy: string; definitions: TaskTypeDictionary; - unusedTypes: string[]; taskStore: TaskStore; maxAttempts: number; excludedTaskTypes: string[]; @@ -92,7 +91,6 @@ export class TaskClaiming { private readonly taskClaimingBatchesByType: TaskClaimingBatches; private readonly taskMaxAttempts: Record; private readonly excludedTaskTypes: string[]; - private readonly unusedTypes: string[]; private readonly taskClaimer: TaskClaimerFn; private readonly taskPartitioner: TaskPartitioner; @@ -111,7 +109,6 @@ export class TaskClaiming { this.taskClaimingBatchesByType = this.partitionIntoClaimingBatches(this.definitions); this.taskMaxAttempts = Object.fromEntries(this.normalizeMaxAttempts(this.definitions)); this.excludedTaskTypes = opts.excludedTaskTypes; - this.unusedTypes = opts.unusedTypes; this.taskClaimer = getTaskClaimer(this.logger, opts.strategy); this.events$ = new Subject(); this.taskPartitioner = opts.taskPartitioner; @@ -178,7 +175,6 @@ export class TaskClaiming { taskStore: this.taskStore, events$: this.events$, getCapacity: this.getAvailableCapacity, - unusedTypes: this.unusedTypes, definitions: this.definitions, taskMaxAttempts: this.taskMaxAttempts, excludedTaskTypes: this.excludedTaskTypes, diff --git a/x-pack/plugins/task_manager/server/removed_tasks/mark_removed_tasks_as_unrecognized.test.ts b/x-pack/plugins/task_manager/server/removed_tasks/mark_removed_tasks_as_unrecognized.test.ts new file mode 100644 index 000000000000..1485216a67f3 --- /dev/null +++ b/x-pack/plugins/task_manager/server/removed_tasks/mark_removed_tasks_as_unrecognized.test.ts @@ -0,0 +1,266 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mockLogger } from '../test_utils'; +import { coreMock, elasticsearchServiceMock } from '@kbn/core/server/mocks'; +import { SCHEDULE_INTERVAL, taskRunner } from './mark_removed_tasks_as_unrecognized'; +import { SearchHit } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +const createTaskDoc = (id: string = '1'): SearchHit => ({ + _index: '.kibana_task_manager_9.0.0_001', + _id: `task:${id}`, + _score: 1, + _source: { + references: [], + type: 'task', + updated_at: '2024-11-06T14:17:55.935Z', + task: { + taskType: 'report', + params: '{}', + state: '{"foo":"test"}', + stateVersion: 1, + runAt: '2024-11-06T14:17:55.935Z', + enabled: true, + scheduledAt: '2024-11-06T14:17:55.935Z', + attempts: 0, + status: 'idle', + startedAt: null, + retryAt: null, + ownerId: null, + partition: 211, + }, + }, +}); + +describe('markRemovedTasksAsUnrecognizedTask', () => { + const logger = mockLogger(); + const coreSetup = coreMock.createSetup(); + const esClient = elasticsearchServiceMock.createStart(); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('marks removed tasks as unrecognized', async () => { + esClient.client.asInternalUser.bulk.mockResolvedValue({ + errors: false, + took: 0, + items: [ + { + update: { + _index: '.kibana_task_manager_9.0.0_001', + _id: 'task:123', + _version: 2, + result: 'updated', + _shards: { total: 1, successful: 1, failed: 0 }, + _seq_no: 84, + _primary_term: 1, + status: 200, + }, + }, + { + update: { + _index: '.kibana_task_manager_9.0.0_001', + _id: 'task:456', + _version: 2, + result: 'updated', + _shards: { total: 1, successful: 1, failed: 0 }, + _seq_no: 84, + _primary_term: 1, + status: 200, + }, + }, + { + update: { + _index: '.kibana_task_manager_9.0.0_001', + _id: 'task:789', + _version: 2, + result: 'updated', + _shards: { total: 1, successful: 1, failed: 0 }, + _seq_no: 84, + _primary_term: 1, + status: 200, + }, + }, + ], + }); + + coreSetup.getStartServices.mockResolvedValue([ + { + ...coreMock.createStart(), + elasticsearch: esClient, + }, + {}, + coreMock.createSetup(), + ]); + // @ts-expect-error + esClient.client.asInternalUser.search.mockResponse({ + hits: { hits: [createTaskDoc('123'), createTaskDoc('456'), createTaskDoc('789')], total: 3 }, + }); + + const runner = taskRunner(logger, coreSetup.getStartServices)(); + const result = await runner.run(); + + expect(esClient.client.asInternalUser.bulk).toHaveBeenCalledWith({ + body: [ + { update: { _id: 'task:123' } }, + { doc: { task: { status: 'unrecognized' } } }, + { update: { _id: 'task:456' } }, + { doc: { task: { status: 'unrecognized' } } }, + { update: { _id: 'task:789' } }, + { doc: { task: { status: 'unrecognized' } } }, + ], + index: '.kibana_task_manager', + refresh: false, + }); + + expect(logger.debug).toHaveBeenCalledWith(`Marked 3 removed tasks as unrecognized`); + + expect(result).toEqual({ + state: {}, + schedule: { interval: SCHEDULE_INTERVAL }, + }); + }); + + it('skips update when there are no removed task types', async () => { + coreSetup.getStartServices.mockResolvedValue([ + { + ...coreMock.createStart(), + elasticsearch: esClient, + }, + {}, + coreMock.createSetup(), + ]); + // @ts-expect-error + esClient.client.asInternalUser.search.mockResponse({ + hits: { hits: [], total: 0 }, + }); + + const runner = taskRunner(logger, coreSetup.getStartServices)(); + const result = await runner.run(); + + expect(esClient.client.asInternalUser.bulk).not.toHaveBeenCalled(); + + expect(result).toEqual({ + state: {}, + schedule: { interval: SCHEDULE_INTERVAL }, + }); + }); + + it('schedules the next run even when there is an error', async () => { + coreSetup.getStartServices.mockResolvedValue([ + { + ...coreMock.createStart(), + elasticsearch: esClient, + }, + {}, + coreMock.createSetup(), + ]); + esClient.client.asInternalUser.search.mockRejectedValueOnce(new Error('foo')); + + const runner = taskRunner(logger, coreSetup.getStartServices)(); + const result = await runner.run(); + + expect(esClient.client.asInternalUser.bulk).not.toHaveBeenCalled(); + + expect(logger.error).toHaveBeenCalledWith( + 'Failed to mark removed tasks as unrecognized. Error: foo' + ); + + expect(result).toEqual({ + state: {}, + schedule: { interval: SCHEDULE_INTERVAL }, + }); + }); + + it('handles partial errors from bulk partial update', async () => { + esClient.client.asInternalUser.bulk.mockResolvedValue({ + errors: false, + took: 0, + items: [ + { + update: { + _index: '.kibana_task_manager_9.0.0_001', + _id: 'task:123', + _version: 2, + result: 'updated', + _shards: { total: 1, successful: 1, failed: 0 }, + _seq_no: 84, + _primary_term: 1, + status: 200, + }, + }, + { + update: { + _index: '.kibana_task_manager_9.0.0_001', + _id: 'task:456', + _version: 2, + result: 'updated', + _shards: { total: 1, successful: 1, failed: 0 }, + _seq_no: 84, + _primary_term: 1, + status: 200, + }, + }, + { + update: { + _index: '.kibana_task_manager_9.0.0_001', + _id: 'task:789', + _version: 2, + error: { + type: 'document_missing_exception', + reason: '[5]: document missing', + index_uuid: 'aAsFqTI0Tc2W0LCWgPNrOA', + shard: '0', + index: '.kibana_task_manager_9.0.0_001', + }, + status: 404, + }, + }, + ], + }); + + coreSetup.getStartServices.mockResolvedValue([ + { + ...coreMock.createStart(), + elasticsearch: esClient, + }, + {}, + coreMock.createSetup(), + ]); + // @ts-expect-error + esClient.client.asInternalUser.search.mockResponse({ + hits: { hits: [createTaskDoc('123'), createTaskDoc('456'), createTaskDoc('789')], total: 3 }, + }); + + const runner = taskRunner(logger, coreSetup.getStartServices)(); + const result = await runner.run(); + + expect(esClient.client.asInternalUser.bulk).toHaveBeenCalledWith({ + body: [ + { update: { _id: 'task:123' } }, + { doc: { task: { status: 'unrecognized' } } }, + { update: { _id: 'task:456' } }, + { doc: { task: { status: 'unrecognized' } } }, + { update: { _id: 'task:789' } }, + { doc: { task: { status: 'unrecognized' } } }, + ], + index: '.kibana_task_manager', + refresh: false, + }); + expect(logger.warn).toHaveBeenCalledWith( + `Error updating task task:789 to mark as unrecognized - {\"type\":\"document_missing_exception\",\"reason\":\"[5]: document missing\",\"index_uuid\":\"aAsFqTI0Tc2W0LCWgPNrOA\",\"shard\":\"0\",\"index\":\".kibana_task_manager_9.0.0_001\"}` + ); + + expect(logger.debug).toHaveBeenCalledWith(`Marked 2 removed tasks as unrecognized`); + + expect(result).toEqual({ + state: {}, + schedule: { interval: SCHEDULE_INTERVAL }, + }); + }); +}); diff --git a/x-pack/plugins/task_manager/server/removed_tasks/mark_removed_tasks_as_unrecognized.ts b/x-pack/plugins/task_manager/server/removed_tasks/mark_removed_tasks_as_unrecognized.ts new file mode 100644 index 000000000000..e28d5221e72d --- /dev/null +++ b/x-pack/plugins/task_manager/server/removed_tasks/mark_removed_tasks_as_unrecognized.ts @@ -0,0 +1,150 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Logger } from '@kbn/logging'; +import { CoreStart } from '@kbn/core-lifecycle-server'; +import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { SearchHit } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { TaskScheduling } from '../task_scheduling'; +import { TaskTypeDictionary } from '../task_type_dictionary'; +import { ConcreteTaskInstance, TaskManagerStartContract } from '..'; +import { TaskStatus } from '../task'; +import { REMOVED_TYPES } from '../task_type_dictionary'; +import { TASK_MANAGER_INDEX } from '../constants'; + +export const TASK_ID = 'mark_removed_tasks_as_unrecognized'; +const TASK_TYPE = `task_manager:${TASK_ID}`; + +export const SCHEDULE_INTERVAL = '1h'; + +export async function scheduleMarkRemovedTasksAsUnrecognizedDefinition( + logger: Logger, + taskScheduling: TaskScheduling +) { + try { + await taskScheduling.ensureScheduled({ + id: TASK_ID, + taskType: TASK_TYPE, + schedule: { interval: SCHEDULE_INTERVAL }, + state: {}, + params: {}, + }); + } catch (e) { + logger.error(`Error scheduling ${TASK_ID} task, received ${e.message}`); + } +} + +export function registerMarkRemovedTasksAsUnrecognizedDefinition( + logger: Logger, + coreStartServices: () => Promise<[CoreStart, TaskManagerStartContract, unknown]>, + taskTypeDictionary: TaskTypeDictionary +) { + taskTypeDictionary.registerTaskDefinitions({ + [TASK_TYPE]: { + title: 'Mark removed tasks as unrecognized', + createTaskRunner: taskRunner(logger, coreStartServices), + }, + }); +} + +export function taskRunner( + logger: Logger, + coreStartServices: () => Promise<[CoreStart, TaskManagerStartContract, unknown]> +) { + return () => { + return { + async run() { + try { + const [{ elasticsearch }] = await coreStartServices(); + const esClient = elasticsearch.client.asInternalUser; + + const removedTasks = await queryForRemovedTasks(esClient); + + if (removedTasks.length > 0) { + await updateTasksToBeUnrecognized(esClient, logger, removedTasks); + } + + return { + state: {}, + schedule: { interval: SCHEDULE_INTERVAL }, + }; + } catch (e) { + logger.error(`Failed to mark removed tasks as unrecognized. Error: ${e.message}`); + return { + state: {}, + schedule: { interval: SCHEDULE_INTERVAL }, + }; + } + }, + }; + }; +} + +async function queryForRemovedTasks( + esClient: ElasticsearchClient +): Promise>> { + const result = await esClient.search({ + index: TASK_MANAGER_INDEX, + body: { + size: 100, + _source: false, + query: { + bool: { + must: [ + { + terms: { + 'task.taskType': REMOVED_TYPES, + }, + }, + ], + }, + }, + }, + }); + + return result.hits.hits; +} + +async function updateTasksToBeUnrecognized( + esClient: ElasticsearchClient, + logger: Logger, + removedTasks: Array> +) { + const bulkBody = []; + for (const task of removedTasks) { + bulkBody.push({ update: { _id: task._id } }); + bulkBody.push({ doc: { task: { status: TaskStatus.Unrecognized } } }); + } + + let removedCount = 0; + try { + const removeResults = await esClient.bulk({ + index: TASK_MANAGER_INDEX, + refresh: false, + body: bulkBody, + }); + for (const removeResult of removeResults.items) { + if (!removeResult.update || !removeResult.update._id) { + logger.warn( + `Error updating task with unknown to mark as unrecognized - malformed response` + ); + } else if (removeResult.update?.error) { + logger.warn( + `Error updating task ${ + removeResult.update._id + } to mark as unrecognized - ${JSON.stringify(removeResult.update.error)}` + ); + } else { + removedCount++; + } + } + logger.debug(`Marked ${removedCount} removed tasks as unrecognized`); + } catch (err) { + // don't worry too much about errors, we'll try again next time + logger.warn(`Error updating tasks to mark as unrecognized: ${err}`); + } +} diff --git a/x-pack/plugins/task_manager/server/task_claimers/index.ts b/x-pack/plugins/task_manager/server/task_claimers/index.ts index 178ebacf68cb..f41c489fd755 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/index.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/index.ts @@ -26,7 +26,6 @@ export interface TaskClaimerOpts { events$: Subject; taskStore: TaskStore; definitions: TaskTypeDictionary; - unusedTypes: string[]; excludedTaskTypes: string[]; taskMaxAttempts: Record; logger: Logger; diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.test.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.test.ts index e089d3b2d878..07dae3c48a39 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.test.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.test.ts @@ -11,6 +11,7 @@ import { v4 as uuidv4 } from 'uuid'; import { filter, take } from 'rxjs'; import { CLAIM_STRATEGY_MGET, DEFAULT_KIBANAS_PER_PARTITION } from '../config'; +import { NO_ASSIGNED_PARTITIONS_WARNING_INTERVAL } from './strategy_mget'; import { TaskStatus, @@ -189,7 +190,6 @@ describe('TaskClaiming', () => { definitions, taskStore: store, excludedTaskTypes, - unusedTypes: unusedTaskTypes, maxAttempts: taskClaimingOpts.maxAttempts ?? 2, getAvailableCapacity: taskClaimingOpts.getAvailableCapacity ?? (() => 10), taskPartitioner, @@ -205,20 +205,17 @@ describe('TaskClaiming', () => { claimingOpts, hits = [generateFakeTasks(1)], excludedTaskTypes = [], - unusedTaskTypes = [], }: { storeOpts: Partial; taskClaimingOpts: Partial; claimingOpts: Omit; hits?: ConcreteTaskInstance[][]; excludedTaskTypes?: string[]; - unusedTaskTypes?: string[]; }) { const { taskClaiming, store } = initialiseTestClaiming({ storeOpts, taskClaimingOpts, excludedTaskTypes, - unusedTaskTypes, hits, }); @@ -354,7 +351,6 @@ describe('TaskClaiming', () => { definitions: taskDefinitions, taskStore: store, excludedTaskTypes: [], - unusedTypes: [], maxAttempts: 2, getAvailableCapacity: () => 10, taskPartitioner, @@ -377,7 +373,7 @@ describe('TaskClaiming', () => { expect(mockApmTrans.end).toHaveBeenCalledWith('success'); expect(taskManagerLogger.debug).toHaveBeenCalledWith( - 'task claimer claimed: 3; stale: 0; conflicts: 0; missing: 0; capacity reached: 3; updateErrors: 0; getErrors: 0; removed: 0;', + 'task claimer claimed: 3; stale: 0; conflicts: 0; missing: 0; capacity reached: 3; updateErrors: 0; getErrors: 0;', { tags: ['taskClaiming', 'claimAvailableTasksMget'] } ); @@ -439,312 +435,6 @@ describe('TaskClaiming', () => { expect(result.docs.length).toEqual(3); }); - test('should not claim tasks of removed type', async () => { - const store = taskStoreMock.create({ taskManagerId: 'test-test' }); - store.convertToSavedObjectIds.mockImplementation((ids) => ids.map((id) => `task:${id}`)); - - const fetchedTasks = [ - mockInstance({ id: `id-1`, taskType: 'report' }), - mockInstance({ id: `id-2`, taskType: 'report' }), - mockInstance({ id: `id-3`, taskType: 'yawn' }), - ]; - - const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); - store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); - store.getDocVersions.mockResolvedValueOnce(docLatestVersions); - - store.bulkGet.mockResolvedValueOnce([fetchedTasks[2]].map(asOk)); - store.bulkPartialUpdate.mockResolvedValueOnce([fetchedTasks[2]].map(getPartialUpdateResult)); - store.bulkPartialUpdate.mockResolvedValueOnce( - [fetchedTasks[0], fetchedTasks[1]].map(getPartialUpdateResult) - ); - - const taskClaiming = new TaskClaiming({ - logger: taskManagerLogger, - strategy: CLAIM_STRATEGY_MGET, - definitions: taskDefinitions, - taskStore: store, - excludedTaskTypes: [], - unusedTypes: ['report'], - maxAttempts: 2, - getAvailableCapacity: () => 10, - taskPartitioner, - }); - - const resultOrErr = await taskClaiming.claimAvailableTasksIfCapacityIsAvailable({ - claimOwnershipUntil: new Date(), - }); - - if (!isOk(resultOrErr)) { - expect(resultOrErr).toBe(undefined); - } - - const result = unwrap(resultOrErr) as ClaimOwnershipResult; - - expect(apm.startTransaction).toHaveBeenCalledWith( - TASK_MANAGER_MARK_AS_CLAIMED, - TASK_MANAGER_TRANSACTION_TYPE - ); - expect(mockApmTrans.end).toHaveBeenCalledWith('success'); - - expect(taskManagerLogger.debug).toHaveBeenCalledWith( - 'task claimer claimed: 1; stale: 0; conflicts: 0; missing: 0; capacity reached: 0; updateErrors: 0; getErrors: 0; removed: 2;', - { tags: ['taskClaiming', 'claimAvailableTasksMget'] } - ); - - expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ - size: 40, - seq_no_primary_term: true, - }); - expect(store.getDocVersions).toHaveBeenCalledWith(['task:id-1', 'task:id-2', 'task:id-3']); - expect(store.bulkPartialUpdate).toHaveBeenCalledTimes(2); - expect(store.bulkPartialUpdate).toHaveBeenNthCalledWith(1, [ - { - id: fetchedTasks[2].id, - version: fetchedTasks[2].version, - scheduledAt: fetchedTasks[2].runAt, - attempts: 1, - ownerId: 'test-test', - retryAt: new Date('1970-01-01T00:05:30.000Z'), - status: 'running', - startedAt: new Date('1970-01-01T00:00:00.000Z'), - }, - ]); - expect(store.bulkPartialUpdate).toHaveBeenNthCalledWith(2, [ - { - id: fetchedTasks[0].id, - version: fetchedTasks[0].version, - status: 'unrecognized', - }, - { - id: fetchedTasks[1].id, - version: fetchedTasks[1].version, - status: 'unrecognized', - }, - ]); - expect(store.bulkGet).toHaveBeenCalledWith(['id-3']); - - expect(result.stats).toEqual({ - tasksClaimed: 1, - tasksConflicted: 0, - tasksErrors: 0, - tasksUpdated: 1, - tasksLeftUnclaimed: 0, - staleTasks: 0, - }); - expect(result.docs.length).toEqual(1); - }); - - test('should log warning if error updating single removed task as unrecognized', async () => { - const store = taskStoreMock.create({ taskManagerId: 'test-test' }); - store.convertToSavedObjectIds.mockImplementation((ids) => ids.map((id) => `task:${id}`)); - - const fetchedTasks = [ - mockInstance({ id: `id-1`, taskType: 'report' }), - mockInstance({ id: `id-2`, taskType: 'report' }), - mockInstance({ id: `id-3`, taskType: 'yawn' }), - ]; - - const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); - store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); - store.getDocVersions.mockResolvedValueOnce(docLatestVersions); - - store.bulkGet.mockResolvedValueOnce([fetchedTasks[2]].map(asOk)); - store.bulkPartialUpdate.mockResolvedValueOnce([fetchedTasks[2]].map(getPartialUpdateResult)); - store.bulkPartialUpdate.mockResolvedValueOnce([ - asOk(fetchedTasks[0]), - asErr({ - type: 'task', - id: fetchedTasks[1].id, - status: 404, - error: { - type: 'document_missing_exception', - reason: '[5]: document missing', - index_uuid: 'aAsFqTI0Tc2W0LCWgPNrOA', - shard: '0', - index: '.kibana_task_manager_8.16.0_001', - }, - }), - ]); - - const taskClaiming = new TaskClaiming({ - logger: taskManagerLogger, - strategy: CLAIM_STRATEGY_MGET, - definitions: taskDefinitions, - taskStore: store, - excludedTaskTypes: [], - unusedTypes: ['report'], - maxAttempts: 2, - getAvailableCapacity: () => 10, - taskPartitioner, - }); - - const resultOrErr = await taskClaiming.claimAvailableTasksIfCapacityIsAvailable({ - claimOwnershipUntil: new Date(), - }); - - if (!isOk(resultOrErr)) { - expect(resultOrErr).toBe(undefined); - } - - const result = unwrap(resultOrErr) as ClaimOwnershipResult; - - expect(apm.startTransaction).toHaveBeenCalledWith( - TASK_MANAGER_MARK_AS_CLAIMED, - TASK_MANAGER_TRANSACTION_TYPE - ); - expect(mockApmTrans.end).toHaveBeenCalledWith('success'); - - expect(taskManagerLogger.warn).toHaveBeenCalledWith( - 'Error updating task id-2:task to mark as unrecognized during claim: {"type":"document_missing_exception","reason":"[5]: document missing","index_uuid":"aAsFqTI0Tc2W0LCWgPNrOA","shard":"0","index":".kibana_task_manager_8.16.0_001"}', - { tags: ['taskClaiming', 'claimAvailableTasksMget'] } - ); - expect(taskManagerLogger.debug).toHaveBeenCalledWith( - 'task claimer claimed: 1; stale: 0; conflicts: 0; missing: 0; capacity reached: 0; updateErrors: 0; getErrors: 0; removed: 1;', - { tags: ['taskClaiming', 'claimAvailableTasksMget'] } - ); - - expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ - size: 40, - seq_no_primary_term: true, - }); - expect(store.getDocVersions).toHaveBeenCalledWith(['task:id-1', 'task:id-2', 'task:id-3']); - expect(store.bulkPartialUpdate).toHaveBeenCalledTimes(2); - expect(store.bulkPartialUpdate).toHaveBeenNthCalledWith(1, [ - { - id: fetchedTasks[2].id, - version: fetchedTasks[2].version, - scheduledAt: fetchedTasks[2].runAt, - attempts: 1, - ownerId: 'test-test', - retryAt: new Date('1970-01-01T00:05:30.000Z'), - status: 'running', - startedAt: new Date('1970-01-01T00:00:00.000Z'), - }, - ]); - expect(store.bulkPartialUpdate).toHaveBeenNthCalledWith(2, [ - { - id: fetchedTasks[0].id, - version: fetchedTasks[0].version, - status: 'unrecognized', - }, - { - id: fetchedTasks[1].id, - version: fetchedTasks[1].version, - status: 'unrecognized', - }, - ]); - expect(store.bulkGet).toHaveBeenCalledWith(['id-3']); - - expect(result.stats).toEqual({ - tasksClaimed: 1, - tasksConflicted: 0, - tasksErrors: 0, - tasksUpdated: 1, - tasksLeftUnclaimed: 0, - staleTasks: 0, - }); - expect(result.docs.length).toEqual(1); - }); - - test('should log warning if error updating all removed tasks as unrecognized', async () => { - const store = taskStoreMock.create({ taskManagerId: 'test-test' }); - store.convertToSavedObjectIds.mockImplementation((ids) => ids.map((id) => `task:${id}`)); - - const fetchedTasks = [ - mockInstance({ id: `id-1`, taskType: 'report' }), - mockInstance({ id: `id-2`, taskType: 'report' }), - mockInstance({ id: `id-3`, taskType: 'yawn' }), - ]; - - const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); - store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); - store.getDocVersions.mockResolvedValueOnce(docLatestVersions); - - store.bulkGet.mockResolvedValueOnce([fetchedTasks[2]].map(asOk)); - store.bulkPartialUpdate.mockResolvedValueOnce([fetchedTasks[2]].map(getPartialUpdateResult)); - store.bulkPartialUpdate.mockRejectedValueOnce(new Error('Oh no')); - - const taskClaiming = new TaskClaiming({ - logger: taskManagerLogger, - strategy: CLAIM_STRATEGY_MGET, - definitions: taskDefinitions, - taskStore: store, - excludedTaskTypes: [], - unusedTypes: ['report'], - maxAttempts: 2, - getAvailableCapacity: () => 10, - taskPartitioner, - }); - - const resultOrErr = await taskClaiming.claimAvailableTasksIfCapacityIsAvailable({ - claimOwnershipUntil: new Date(), - }); - - if (!isOk(resultOrErr)) { - expect(resultOrErr).toBe(undefined); - } - - const result = unwrap(resultOrErr) as ClaimOwnershipResult; - - expect(apm.startTransaction).toHaveBeenCalledWith( - TASK_MANAGER_MARK_AS_CLAIMED, - TASK_MANAGER_TRANSACTION_TYPE - ); - expect(mockApmTrans.end).toHaveBeenCalledWith('success'); - - expect(taskManagerLogger.warn).toHaveBeenCalledWith( - 'Error updating tasks to mark as unrecognized during claim: Error: Oh no', - { tags: ['taskClaiming', 'claimAvailableTasksMget'] } - ); - expect(taskManagerLogger.debug).toHaveBeenCalledWith( - 'task claimer claimed: 1; stale: 0; conflicts: 0; missing: 0; capacity reached: 0; updateErrors: 0; getErrors: 0; removed: 0;', - { tags: ['taskClaiming', 'claimAvailableTasksMget'] } - ); - - expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ - size: 40, - seq_no_primary_term: true, - }); - expect(store.getDocVersions).toHaveBeenCalledWith(['task:id-1', 'task:id-2', 'task:id-3']); - expect(store.bulkGet).toHaveBeenCalledWith(['id-3']); - expect(store.bulkPartialUpdate).toHaveBeenCalledTimes(2); - expect(store.bulkPartialUpdate).toHaveBeenNthCalledWith(1, [ - { - id: fetchedTasks[2].id, - version: fetchedTasks[2].version, - scheduledAt: fetchedTasks[2].runAt, - attempts: 1, - ownerId: 'test-test', - retryAt: new Date('1970-01-01T00:05:30.000Z'), - status: 'running', - startedAt: new Date('1970-01-01T00:00:00.000Z'), - }, - ]); - expect(store.bulkPartialUpdate).toHaveBeenNthCalledWith(2, [ - { - id: fetchedTasks[0].id, - version: fetchedTasks[0].version, - status: 'unrecognized', - }, - { - id: fetchedTasks[1].id, - version: fetchedTasks[1].version, - status: 'unrecognized', - }, - ]); - - expect(result.stats).toEqual({ - tasksClaimed: 1, - tasksConflicted: 0, - tasksErrors: 0, - tasksUpdated: 1, - tasksLeftUnclaimed: 0, - staleTasks: 0, - }); - expect(result.docs.length).toEqual(1); - }); - test('should handle no tasks to claim', async () => { const store = taskStoreMock.create({ taskManagerId: 'test-test' }); store.convertToSavedObjectIds.mockImplementation((ids) => ids.map((id) => `task:${id}`)); @@ -760,7 +450,6 @@ describe('TaskClaiming', () => { definitions: taskDefinitions, taskStore: store, excludedTaskTypes: [], - unusedTypes: [], maxAttempts: 2, getAvailableCapacity: () => 10, taskPartitioner, @@ -827,7 +516,6 @@ describe('TaskClaiming', () => { definitions: taskDefinitions, taskStore: store, excludedTaskTypes: [], - unusedTypes: [], maxAttempts: 2, getAvailableCapacity: () => 10, taskPartitioner, @@ -850,7 +538,7 @@ describe('TaskClaiming', () => { expect(mockApmTrans.end).toHaveBeenCalledWith('success'); expect(taskManagerLogger.debug).toHaveBeenCalledWith( - 'task claimer claimed: 2; stale: 0; conflicts: 0; missing: 1; capacity reached: 0; updateErrors: 0; getErrors: 0; removed: 0;', + 'task claimer claimed: 2; stale: 0; conflicts: 0; missing: 1; capacity reached: 0; updateErrors: 0; getErrors: 0;', { tags: ['taskClaiming', 'claimAvailableTasksMget'] } ); @@ -921,7 +609,6 @@ describe('TaskClaiming', () => { definitions: taskDefinitions, taskStore: store, excludedTaskTypes: [], - unusedTypes: [], maxAttempts: 2, getAvailableCapacity: () => 10, taskPartitioner, @@ -944,7 +631,7 @@ describe('TaskClaiming', () => { expect(mockApmTrans.end).toHaveBeenCalledWith('success'); expect(taskManagerLogger.debug).toHaveBeenCalledWith( - 'task claimer claimed: 2; stale: 0; conflicts: 0; missing: 1; capacity reached: 0; updateErrors: 0; getErrors: 0; removed: 0;', + 'task claimer claimed: 2; stale: 0; conflicts: 0; missing: 1; capacity reached: 0; updateErrors: 0; getErrors: 0;', { tags: ['taskClaiming', 'claimAvailableTasksMget'] } ); @@ -1015,7 +702,6 @@ describe('TaskClaiming', () => { definitions: taskDefinitions, taskStore: store, excludedTaskTypes: [], - unusedTypes: [], maxAttempts: 2, getAvailableCapacity: () => 10, taskPartitioner, @@ -1038,7 +724,7 @@ describe('TaskClaiming', () => { expect(mockApmTrans.end).toHaveBeenCalledWith('success'); expect(taskManagerLogger.debug).toHaveBeenCalledWith( - 'task claimer claimed: 2; stale: 1; conflicts: 0; missing: 0; capacity reached: 0; updateErrors: 0; getErrors: 0; removed: 0;', + 'task claimer claimed: 2; stale: 1; conflicts: 0; missing: 0; capacity reached: 0; updateErrors: 0; getErrors: 0;', { tags: ['taskClaiming', 'claimAvailableTasksMget'] } ); @@ -1115,7 +801,6 @@ describe('TaskClaiming', () => { definitions: taskDefinitions, taskStore: store, excludedTaskTypes: [], - unusedTypes: [], maxAttempts: 2, getAvailableCapacity: () => 10, taskPartitioner, @@ -1138,7 +823,7 @@ describe('TaskClaiming', () => { expect(mockApmTrans.end).toHaveBeenCalledWith('success'); expect(taskManagerLogger.debug).toHaveBeenCalledWith( - 'task claimer claimed: 4; stale: 0; conflicts: 0; missing: 0; capacity reached: 0; updateErrors: 0; getErrors: 0; removed: 0;', + 'task claimer claimed: 4; stale: 0; conflicts: 0; missing: 0; capacity reached: 0; updateErrors: 0; getErrors: 0;', { tags: ['taskClaiming', 'claimAvailableTasksMget'] } ); @@ -1247,7 +932,6 @@ describe('TaskClaiming', () => { definitions: taskDefinitions, taskStore: store, excludedTaskTypes: [], - unusedTypes: [], maxAttempts: 2, getAvailableCapacity: () => 10, taskPartitioner, @@ -1270,7 +954,7 @@ describe('TaskClaiming', () => { expect(mockApmTrans.end).toHaveBeenCalledWith('success'); expect(taskManagerLogger.debug).toHaveBeenCalledWith( - 'task claimer claimed: 3; stale: 0; conflicts: 0; missing: 0; capacity reached: 0; updateErrors: 0; getErrors: 1; removed: 0;', + 'task claimer claimed: 3; stale: 0; conflicts: 0; missing: 0; capacity reached: 0; updateErrors: 0; getErrors: 1;', { tags: ['taskClaiming', 'claimAvailableTasksMget'] } ); expect(taskManagerLogger.error).toHaveBeenCalledWith( @@ -1344,15 +1028,15 @@ describe('TaskClaiming', () => { expect(result.docs.length).toEqual(3); }); - test('should assign startedAt value if bulkGet returns task with null startedAt', async () => { + test('should skip tasks where bulkGet returns a newer task document than the bulkPartialUpdate', async () => { const store = taskStoreMock.create({ taskManagerId: 'test-test' }); store.convertToSavedObjectIds.mockImplementation((ids) => ids.map((id) => `task:${id}`)); const fetchedTasks = [ - mockInstance({ id: `id-1`, taskType: 'report' }), - mockInstance({ id: `id-2`, taskType: 'report' }), - mockInstance({ id: `id-3`, taskType: 'yawn' }), - mockInstance({ id: `id-4`, taskType: 'report' }), + mockInstance({ id: `id-1`, taskType: 'report', version: '123' }), + mockInstance({ id: `id-2`, taskType: 'report', version: '123' }), + mockInstance({ id: `id-3`, taskType: 'yawn', version: '123' }), + mockInstance({ id: `id-4`, taskType: 'report', version: '123' }), ]; const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); @@ -1365,7 +1049,7 @@ describe('TaskClaiming', () => { ); store.bulkGet.mockResolvedValueOnce([ asOk({ ...fetchedTasks[0], startedAt: new Date() }), - asOk(fetchedTasks[1]), + asOk({ ...fetchedTasks[1], startedAt: new Date(), version: 'abc' }), asOk({ ...fetchedTasks[2], startedAt: new Date() }), asOk({ ...fetchedTasks[3], startedAt: new Date() }), ]); @@ -1376,7 +1060,6 @@ describe('TaskClaiming', () => { definitions: taskDefinitions, taskStore: store, excludedTaskTypes: [], - unusedTypes: [], maxAttempts: 2, getAvailableCapacity: () => 10, taskPartitioner, @@ -1399,11 +1082,11 @@ describe('TaskClaiming', () => { expect(mockApmTrans.end).toHaveBeenCalledWith('success'); expect(taskManagerLogger.debug).toHaveBeenCalledWith( - 'task claimer claimed: 4; stale: 0; conflicts: 0; missing: 0; capacity reached: 0; updateErrors: 0; getErrors: 0; removed: 0;', + 'task claimer claimed: 3; stale: 0; conflicts: 1; missing: 0; capacity reached: 0; updateErrors: 0; getErrors: 0;', { tags: ['taskClaiming', 'claimAvailableTasksMget'] } ); expect(taskManagerLogger.warn).toHaveBeenCalledWith( - 'Task id-2 has a null startedAt value, setting to current time - ownerId null, status idle', + 'Task id-2 was modified during the claiming phase, skipping until the next claiming cycle.', { tags: ['taskClaiming', 'claimAvailableTasksMget'] } ); @@ -1463,14 +1146,14 @@ describe('TaskClaiming', () => { expect(store.bulkGet).toHaveBeenCalledWith(['id-1', 'id-2', 'id-3', 'id-4']); expect(result.stats).toEqual({ - tasksClaimed: 4, - tasksConflicted: 0, + tasksClaimed: 3, + tasksConflicted: 1, tasksErrors: 0, - tasksUpdated: 4, + tasksUpdated: 3, tasksLeftUnclaimed: 0, staleTasks: 0, }); - expect(result.docs.length).toEqual(4); + expect(result.docs.length).toEqual(3); for (const r of result.docs) { expect(r.startedAt).not.toBeNull(); } @@ -1503,7 +1186,6 @@ describe('TaskClaiming', () => { definitions: taskDefinitions, taskStore: store, excludedTaskTypes: [], - unusedTypes: [], maxAttempts: 2, getAvailableCapacity: () => 10, taskPartitioner, @@ -1618,7 +1300,6 @@ describe('TaskClaiming', () => { definitions: taskDefinitions, taskStore: store, excludedTaskTypes: [], - unusedTypes: [], maxAttempts: 2, getAvailableCapacity: () => 10, taskPartitioner, @@ -1641,7 +1322,7 @@ describe('TaskClaiming', () => { expect(mockApmTrans.end).toHaveBeenCalledWith('success'); expect(taskManagerLogger.debug).toHaveBeenCalledWith( - 'task claimer claimed: 3; stale: 0; conflicts: 0; missing: 0; capacity reached: 0; updateErrors: 1; getErrors: 0; removed: 0;', + 'task claimer claimed: 3; stale: 0; conflicts: 0; missing: 0; capacity reached: 0; updateErrors: 1; getErrors: 0;', { tags: ['taskClaiming', 'claimAvailableTasksMget'] } ); expect(taskManagerLogger.error).toHaveBeenCalledWith( @@ -1752,7 +1433,6 @@ describe('TaskClaiming', () => { definitions: taskDefinitions, taskStore: store, excludedTaskTypes: [], - unusedTypes: [], maxAttempts: 2, getAvailableCapacity: () => 10, taskPartitioner, @@ -1775,7 +1455,7 @@ describe('TaskClaiming', () => { expect(mockApmTrans.end).toHaveBeenCalledWith('success'); expect(taskManagerLogger.debug).toHaveBeenCalledWith( - 'task claimer claimed: 3; stale: 0; conflicts: 1; missing: 0; capacity reached: 0; updateErrors: 0; getErrors: 0; removed: 0;', + 'task claimer claimed: 3; stale: 0; conflicts: 1; missing: 0; capacity reached: 0; updateErrors: 0; getErrors: 0;', { tags: ['taskClaiming', 'claimAvailableTasksMget'] } ); expect(taskManagerLogger.error).not.toHaveBeenCalled(); @@ -1869,7 +1549,6 @@ describe('TaskClaiming', () => { definitions: taskDefinitions, taskStore: store, excludedTaskTypes: [], - unusedTypes: [], maxAttempts: 2, getAvailableCapacity: () => 10, taskPartitioner, @@ -2260,6 +1939,129 @@ describe('TaskClaiming', () => { } `); }); + + test(`it should log warning on interval when the node has no assigned partitions`, async () => { + // Reset the warning timer by advancing more + fakeTimer.tick(NO_ASSIGNED_PARTITIONS_WARNING_INTERVAL); + + jest.spyOn(taskPartitioner, 'getPartitions').mockResolvedValue([]); + const taskManagerId = uuidv4(); + const definitions = new TaskTypeDictionary(mockLogger()); + definitions.registerTaskDefinitions({ + foo: { + title: 'foo', + createTaskRunner: jest.fn(), + }, + bar: { + title: 'bar', + createTaskRunner: jest.fn(), + }, + }); + await testClaimAvailableTasks({ + storeOpts: { + taskManagerId, + definitions, + }, + taskClaimingOpts: {}, + claimingOpts: { + claimOwnershipUntil: new Date(), + }, + }); + + expect(taskManagerLogger.warn).toHaveBeenCalledWith( + 'Background task node "test" has no assigned partitions, claiming against all partitions', + { tags: ['taskClaiming', 'claimAvailableTasksMget'] } + ); + + taskManagerLogger.warn.mockReset(); + fakeTimer.tick(NO_ASSIGNED_PARTITIONS_WARNING_INTERVAL - 500); + + await testClaimAvailableTasks({ + storeOpts: { + taskManagerId, + definitions, + }, + taskClaimingOpts: {}, + claimingOpts: { + claimOwnershipUntil: new Date(), + }, + }); + + expect(taskManagerLogger.warn).not.toHaveBeenCalled(); + + fakeTimer.tick(500); + + await testClaimAvailableTasks({ + storeOpts: { + taskManagerId, + definitions, + }, + taskClaimingOpts: {}, + claimingOpts: { + claimOwnershipUntil: new Date(), + }, + }); + + expect(taskManagerLogger.warn).toHaveBeenCalledWith( + 'Background task node "test" has no assigned partitions, claiming against all partitions', + { tags: ['taskClaiming', 'claimAvailableTasksMget'] } + ); + }); + + test(`it should log a message after the node no longer has no assigned partitions`, async () => { + // Reset the warning timer by advancing more + fakeTimer.tick(NO_ASSIGNED_PARTITIONS_WARNING_INTERVAL); + + jest.spyOn(taskPartitioner, 'getPartitions').mockResolvedValue([]); + const taskManagerId = uuidv4(); + const definitions = new TaskTypeDictionary(mockLogger()); + definitions.registerTaskDefinitions({ + foo: { + title: 'foo', + createTaskRunner: jest.fn(), + }, + bar: { + title: 'bar', + createTaskRunner: jest.fn(), + }, + }); + await testClaimAvailableTasks({ + storeOpts: { + taskManagerId, + definitions, + }, + taskClaimingOpts: {}, + claimingOpts: { + claimOwnershipUntil: new Date(), + }, + }); + + expect(taskManagerLogger.warn).toHaveBeenCalledWith( + 'Background task node "test" has no assigned partitions, claiming against all partitions', + { tags: ['taskClaiming', 'claimAvailableTasksMget'] } + ); + + taskManagerLogger.warn.mockReset(); + jest.spyOn(taskPartitioner, 'getPartitions').mockResolvedValue([1, 2, 3]); + fakeTimer.tick(500); + + await testClaimAvailableTasks({ + storeOpts: { + taskManagerId, + definitions, + }, + taskClaimingOpts: {}, + claimingOpts: { + claimOwnershipUntil: new Date(), + }, + }); + + expect(taskManagerLogger.warn).not.toHaveBeenCalled(); + expect(taskManagerLogger.info).toHaveBeenCalledWith( + `Background task node "${taskPartitioner.getPodName()}" now claiming with assigned partitions`, + { tags: ['taskClaiming', 'claimAvailableTasksMget'] } + ); + }); }); describe('task events', () => { @@ -2364,7 +2166,6 @@ describe('TaskClaiming', () => { strategy: CLAIM_STRATEGY_MGET, definitions, excludedTaskTypes: [], - unusedTypes: [], taskStore, maxAttempts: 2, getAvailableCapacity, diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts index 4e74454e8c98..431daab8dd2c 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts @@ -57,7 +57,6 @@ interface OwnershipClaimingOpts { claimOwnershipUntil: Date; size: number; taskTypes: Set; - removedTypes: Set; getCapacity: (taskType?: string | undefined) => number; excludedTaskTypePatterns: string[]; taskStore: TaskStore; @@ -90,19 +89,16 @@ export async function claimAvailableTasksMget( async function claimAvailableTasks(opts: TaskClaimerOpts): Promise { const { getCapacity, claimOwnershipUntil, batches, events$, taskStore, taskPartitioner } = opts; - const { definitions, unusedTypes, excludedTaskTypes, taskMaxAttempts } = opts; + const { definitions, excludedTaskTypes, taskMaxAttempts } = opts; const logger = createWrappedLogger({ logger: opts.logger, tags: [claimAvailableTasksMget.name] }); const initialCapacity = getCapacity(); const stopTaskTimer = startTaskTimer(); - const removedTypes = new Set(unusedTypes); // REMOVED_TYPES - // get a list of candidate tasks to claim, with their version info const { docs, versionMap } = await searchAvailableTasks({ definitions, taskTypes: new Set(definitions.getAllTypes()), excludedTaskTypePatterns: excludedTaskTypes, - removedTypes, taskStore, events$, claimOwnershipUntil, @@ -125,18 +121,12 @@ async function claimAvailableTasks(opts: TaskClaimerOpts): Promise `task:${doc.id}`)); - // filter out stale, missing and removed tasks + // filter out stale and missing tasks const currentTasks: ConcreteTaskInstance[] = []; const staleTasks: ConcreteTaskInstance[] = []; const missingTasks: ConcreteTaskInstance[] = []; - const removedTasks: ConcreteTaskInstance[] = []; for (const searchDoc of docs) { - if (removedTypes.has(searchDoc.taskType)) { - removedTasks.push(searchDoc); - continue; - } - const searchVersion = versionMap.get(searchDoc.id); const latestVersion = docLatestVersions.get(`task:${searchDoc.id}`); if (!searchVersion || !latestVersion) { @@ -195,7 +185,7 @@ async function claimAvailableTasks(opts: TaskClaimerOpts): Promise = {}; let conflicts = 0; let bulkUpdateErrors = 0; let bulkGetErrors = 0; @@ -203,7 +193,7 @@ async function claimAvailableTasks(opts: TaskClaimerOpts): Promise( - (acc, task) => { - if (isOk(task)) { - acc.push(task.value); - } else { - const { id, type, error } = task.error; - logger.error(`Error getting full task ${id}:${type} during claim: ${error.message}`); - bulkGetErrors++; - } - return acc; - }, - [] - ); - - // Look for tasks that have a null startedAt value, log them and manually set a startedAt field - for (const task of fullTasksToRun) { - if (task.startedAt == null) { + const fullTasksToRun = (await taskStore.bulkGet(Object.keys(updatedTasks))).reduce< + ConcreteTaskInstance[] + >((acc, task) => { + if (isOk(task) && task.value.version !== updatedTasks[task.value.id].version) { logger.warn( - `Task ${task.id} has a null startedAt value, setting to current time - ownerId ${task.ownerId}, status ${task.status}` + `Task ${task.value.id} was modified during the claiming phase, skipping until the next claiming cycle.` ); - task.startedAt = now; - } - } - - // separate update for removed tasks; shouldn't happen often, so unlikely - // a performance concern, and keeps the rest of the logic simpler - let removedCount = 0; - if (removedTasks.length > 0) { - const tasksToRemove = Array.from(removedTasks); - const tasksToRemoveUpdates: PartialConcreteTaskInstance[] = []; - for (const task of tasksToRemove) { - tasksToRemoveUpdates.push({ - id: task.id, - status: TaskStatus.Unrecognized, - }); - } - - // don't worry too much about errors, we'll get them next time - try { - const removeResults = await taskStore.bulkPartialUpdate(tasksToRemoveUpdates); - for (const removeResult of removeResults) { - if (isOk(removeResult)) { - removedCount++; - } else { - const { id, type, error } = removeResult.error; - logger.warn( - `Error updating task ${id}:${type} to mark as unrecognized during claim: ${JSON.stringify( - error - )}` - ); - } - } - } catch (err) { - // swallow the error because this is unrelated to the claim cycle - logger.warn(`Error updating tasks to mark as unrecognized during claim: ${err}`); + conflicts++; + } else if (isOk(task)) { + acc.push(task.value); + } else { + const { id, type, error } = task.error; + logger.error(`Error getting full task ${id}:${type} during claim: ${error.message}`); + bulkGetErrors++; } - } + return acc; + }, []); // TODO: need a better way to generate stats - const message = `task claimer claimed: ${fullTasksToRun.length}; stale: ${staleTasks.length}; conflicts: ${conflicts}; missing: ${missingTasks.length}; capacity reached: ${leftOverTasks.length}; updateErrors: ${bulkUpdateErrors}; getErrors: ${bulkGetErrors}; removed: ${removedCount};`; + const message = `task claimer claimed: ${fullTasksToRun.length}; stale: ${staleTasks.length}; conflicts: ${conflicts}; missing: ${missingTasks.length}; capacity reached: ${leftOverTasks.length}; updateErrors: ${bulkUpdateErrors}; getErrors: ${bulkGetErrors};`; logger.debug(message); // build results @@ -306,10 +256,12 @@ interface SearchAvailableTasksResponse { versionMap: Map; } +let lastPartitionWarningLog: number | undefined; +export const NO_ASSIGNED_PARTITIONS_WARNING_INTERVAL = 60000; + async function searchAvailableTasks({ definitions, taskTypes, - removedTypes, excludedTaskTypePatterns, taskStore, getCapacity, @@ -321,15 +273,26 @@ async function searchAvailableTasks({ const claimPartitions = buildClaimPartitions({ types: taskTypes, excludedTaskTypes, - removedTypes, getCapacity, definitions, }); const partitions = await taskPartitioner.getPartitions(); - if (partitions.length === 0) { + if ( + partitions.length === 0 && + (lastPartitionWarningLog == null || + lastPartitionWarningLog <= Date.now() - NO_ASSIGNED_PARTITIONS_WARNING_INTERVAL) + ) { logger.warn( `Background task node "${taskPartitioner.getPodName()}" has no assigned partitions, claiming against all partitions` ); + lastPartitionWarningLog = Date.now(); + } + + if (partitions.length !== 0 && lastPartitionWarningLog) { + lastPartitionWarningLog = undefined; + logger.info( + `Background task node "${taskPartitioner.getPodName()}" now claiming with assigned partitions` + ); } const sort: NonNullable = getClaimSort(definitions); @@ -343,10 +306,7 @@ async function searchAvailableTasks({ // Task must be enabled EnabledTask, // a task type that's not excluded (may be removed or not) - OneOfTaskTypes( - 'task.taskType', - claimPartitions.unlimitedTypes.concat(Array.from(removedTypes)) - ), + OneOfTaskTypes('task.taskType', claimPartitions.unlimitedTypes), // Either a task with idle status and runAt <= now or // status running or claiming with a retryAt <= now. shouldBeOneOf(IdleTaskWithExpiredRunAt, RunningOrClaimingTaskWithExpiredRetryAt), @@ -398,7 +358,6 @@ async function searchAvailableTasks({ } interface ClaimPartitions { - removedTypes: string[]; unlimitedTypes: string[]; limitedTypes: Map; } @@ -406,30 +365,23 @@ interface ClaimPartitions { interface BuildClaimPartitionsOpts { types: Set; excludedTaskTypes: Set; - removedTypes: Set; getCapacity: (taskType?: string) => number; definitions: TaskTypeDictionary; } function buildClaimPartitions(opts: BuildClaimPartitionsOpts): ClaimPartitions { const result: ClaimPartitions = { - removedTypes: [], unlimitedTypes: [], limitedTypes: new Map(), }; - const { types, excludedTaskTypes, removedTypes, getCapacity, definitions } = opts; + const { types, excludedTaskTypes, getCapacity, definitions } = opts; for (const type of types) { const definition = definitions.get(type); if (definition == null) continue; if (excludedTaskTypes.has(type)) continue; - if (removedTypes.has(type)) { - result.removedTypes.push(type); - continue; - } - if (definition.maxConcurrency == null) { result.unlimitedTypes.push(definition.type); continue; diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.test.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.test.ts index 13e6faf2de0f..623693e71c54 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.test.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.test.ts @@ -99,14 +99,12 @@ describe('TaskClaiming', () => { hits = [generateFakeTasks(1)], versionConflicts = 2, excludedTaskTypes = [], - unusedTaskTypes = [], }: { storeOpts: Partial; taskClaimingOpts: Partial; hits?: ConcreteTaskInstance[][]; versionConflicts?: number; excludedTaskTypes?: string[]; - unusedTaskTypes?: string[]; }) { const definitions = storeOpts.definitions ?? taskDefinitions; const store = taskStoreMock.create({ taskManagerId: storeOpts.taskManagerId }); @@ -136,7 +134,6 @@ describe('TaskClaiming', () => { definitions, taskStore: store, excludedTaskTypes, - unusedTypes: unusedTaskTypes, maxAttempts: taskClaimingOpts.maxAttempts ?? 2, getAvailableCapacity: taskClaimingOpts.getAvailableCapacity ?? (() => 10), taskPartitioner, @@ -153,7 +150,6 @@ describe('TaskClaiming', () => { hits = [generateFakeTasks(1)], versionConflicts = 2, excludedTaskTypes = [], - unusedTaskTypes = [], }: { storeOpts: Partial; taskClaimingOpts: Partial; @@ -161,14 +157,12 @@ describe('TaskClaiming', () => { hits?: ConcreteTaskInstance[][]; versionConflicts?: number; excludedTaskTypes?: string[]; - unusedTaskTypes?: string[]; }) { const getCapacity = taskClaimingOpts.getAvailableCapacity ?? (() => 10); const { taskClaiming, store } = initialiseTestClaiming({ storeOpts, taskClaimingOpts, excludedTaskTypes, - unusedTaskTypes, hits, versionConflicts, }); @@ -471,7 +465,6 @@ if (doc['task.runAt'].size()!=0) { 'anotherLimitedToOne', 'limitedToTwo', ], - unusedTaskTypes: [], taskMaxAttempts: { unlimited: maxAttempts, }, @@ -493,7 +486,6 @@ if (doc['task.runAt'].size()!=0) { 'anotherLimitedToOne', 'limitedToTwo', ], - unusedTaskTypes: [], taskMaxAttempts: { limitedToOne: maxAttempts, }, @@ -640,7 +632,6 @@ if (doc['task.runAt'].size()!=0) { }, taskPartitioner, excludedTaskTypes: [], - unusedTypes: [], }); const resultOrErr = await taskClaiming.claimAvailableTasksIfCapacityIsAvailable({ @@ -848,129 +839,6 @@ if (doc['task.runAt'].size()!=0) { expect(firstCycle).not.toMatchObject(secondCycle); }); - test('it passes any unusedTaskTypes to script', async () => { - const maxAttempts = _.random(2, 43); - const customMaxAttempts = _.random(44, 100); - const taskManagerId = uuidv1(); - const fieldUpdates = { - ownerId: taskManagerId, - retryAt: new Date(Date.now()), - }; - const definitions = new TaskTypeDictionary(mockLogger()); - definitions.registerTaskDefinitions({ - foo: { - title: 'foo', - createTaskRunner: jest.fn(), - }, - bar: { - title: 'bar', - maxAttempts: customMaxAttempts, - createTaskRunner: jest.fn(), - }, - foobar: { - title: 'foobar', - maxAttempts: customMaxAttempts, - createTaskRunner: jest.fn(), - }, - }); - - const { - args: { - updateByQuery: [{ query, script }], - }, - } = await testClaimAvailableTasks({ - storeOpts: { - definitions, - taskManagerId, - }, - taskClaimingOpts: { - maxAttempts, - }, - claimingOpts: { - claimOwnershipUntil: new Date(), - }, - excludedTaskTypes: ['foobar'], - unusedTaskTypes: ['barfoo'], - }); - expect(query).toMatchObject({ - bool: { - must: [ - { - bool: { - must: [ - { - term: { - 'task.enabled': true, - }, - }, - ], - }, - }, - { - bool: { - should: [ - { - bool: { - must: [ - { term: { 'task.status': 'idle' } }, - { range: { 'task.runAt': { lte: 'now' } } }, - ], - }, - }, - { - bool: { - must: [ - { - bool: { - should: [ - { term: { 'task.status': 'running' } }, - { term: { 'task.status': 'claiming' } }, - ], - }, - }, - { range: { 'task.retryAt': { lte: 'now' } } }, - ], - }, - }, - ], - }, - }, - ], - filter: [ - { - bool: { - must_not: [ - { - bool: { - should: [ - { term: { 'task.status': 'running' } }, - { term: { 'task.status': 'claiming' } }, - ], - must: { range: { 'task.retryAt': { gt: 'now' } } }, - }, - }, - ], - }, - }, - ], - }, - }); - expect(script).toMatchObject({ - source: expect.any(String), - lang: 'painless', - params: { - fieldUpdates, - claimableTaskTypes: ['foo', 'bar'], - skippedTaskTypes: ['foobar'], - unusedTaskTypes: ['barfoo'], - taskMaxAttempts: { - bar: customMaxAttempts, - foo: maxAttempts, - }, - }, - }); - }); - test('it claims tasks by setting their ownerId, status and retryAt', async () => { const taskManagerId = uuidv1(); const claimOwnershipUntil = new Date(Date.now()); @@ -1356,7 +1224,6 @@ if (doc['task.runAt'].size()!=0) { strategy: 'update_by_query', definitions, excludedTaskTypes: [], - unusedTypes: [], taskStore, maxAttempts: 2, getAvailableCapacity, diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.ts index 5a4bccb43b98..fdfd09e07f9c 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.ts @@ -51,7 +51,6 @@ interface OwnershipClaimingOpts { taskStore: TaskStore; events$: Subject; definitions: TaskTypeDictionary; - unusedTypes: string[]; excludedTaskTypes: string[]; taskMaxAttempts: Record; } @@ -60,7 +59,7 @@ export async function claimAvailableTasksUpdateByQuery( opts: TaskClaimerOpts ): Promise { const { getCapacity, claimOwnershipUntil, batches, events$, taskStore } = opts; - const { definitions, unusedTypes, excludedTaskTypes, taskMaxAttempts } = opts; + const { definitions, excludedTaskTypes, taskMaxAttempts } = opts; const initialCapacity = getCapacity(); let accumulatedResult = getEmptyClaimOwnershipResult(); @@ -83,7 +82,6 @@ export async function claimAvailableTasksUpdateByQuery( taskTypes: isLimited(batch) ? new Set([batch.tasksTypes]) : batch.tasksTypes, taskStore, definitions, - unusedTypes, excludedTaskTypes, taskMaxAttempts, }); @@ -137,7 +135,6 @@ async function markAvailableTasksAsClaimed({ claimOwnershipUntil, size, taskTypes, - unusedTypes, taskMaxAttempts, }: OwnershipClaimingOpts): Promise { const { taskTypesToSkip = [], taskTypesToClaim = [] } = groupBy( @@ -164,7 +161,6 @@ async function markAvailableTasksAsClaimed({ }, claimableTaskTypes: taskTypesToClaim, skippedTaskTypes: taskTypesToSkip, - unusedTaskTypes: unusedTypes, taskMaxAttempts: pick(taskMaxAttempts, taskTypesToClaim), }); diff --git a/x-pack/plugins/task_manager/server/task_store.test.ts b/x-pack/plugins/task_manager/server/task_store.test.ts index 223838155286..cbb1c44dde3f 100644 --- a/x-pack/plugins/task_manager/server/task_store.test.ts +++ b/x-pack/plugins/task_manager/server/task_store.test.ts @@ -1020,7 +1020,10 @@ describe('TaskStore', () => { refresh: false, }); - expect(result).toEqual([asOk(task)]); + expect(result).toEqual([ + // New version returned after update + asOk({ ...task, version: 'Wzg0LDFd' }), + ]); }); test(`should perform partial update with minimal fields`, async () => { @@ -1062,7 +1065,8 @@ describe('TaskStore', () => { refresh: false, }); - expect(result).toEqual([asOk(task)]); + // New version returned after update + expect(result).toEqual([asOk({ ...task, version: 'Wzg0LDFd' })]); }); test(`should perform partial update with no version`, async () => { @@ -1100,7 +1104,8 @@ describe('TaskStore', () => { refresh: false, }); - expect(result).toEqual([asOk(task)]); + // New version returned after update + expect(result).toEqual([asOk({ ...task, version: 'Wzg0LDFd' })]); }); test(`should gracefully handle errors within the response`, async () => { @@ -1183,7 +1188,8 @@ describe('TaskStore', () => { }); expect(result).toEqual([ - asOk(task1), + // New version returned after update + asOk({ ...task1, version: 'Wzg0LDFd' }), asErr({ type: 'task', id: '45343254', @@ -1267,7 +1273,8 @@ describe('TaskStore', () => { }); expect(result).toEqual([ - asOk(task1), + // New version returned after update + asOk({ ...task1, version: 'Wzg0LDFd' }), asErr({ type: 'task', id: 'unknown', diff --git a/x-pack/plugins/task_manager/server/task_store.ts b/x-pack/plugins/task_manager/server/task_store.ts index b7f1cec3f556..0946c5c18d32 100644 --- a/x-pack/plugins/task_manager/server/task_store.ts +++ b/x-pack/plugins/task_manager/server/task_store.ts @@ -26,7 +26,7 @@ import { ElasticsearchClient, } from '@kbn/core/server'; -import { decodeRequestVersion } from '@kbn/core-saved-objects-base-server-internal'; +import { decodeRequestVersion, encodeVersion } from '@kbn/core-saved-objects-base-server-internal'; import { RequestTimeoutsConfig } from './config'; import { asOk, asErr, Result } from './lib/result_type'; @@ -427,6 +427,7 @@ export class TaskStore { return asOk({ ...doc, id: docId, + version: encodeVersion(item.update._seq_no, item.update._primary_term), }); }); } diff --git a/x-pack/plugins/task_manager/tsconfig.json b/x-pack/plugins/task_manager/tsconfig.json index 55ad764c5bdc..b11eaaf44a90 100644 --- a/x-pack/plugins/task_manager/tsconfig.json +++ b/x-pack/plugins/task_manager/tsconfig.json @@ -27,7 +27,8 @@ "@kbn/logging", "@kbn/core-lifecycle-server", "@kbn/cloud-plugin", - "@kbn/core-saved-objects-base-server-internal" + "@kbn/core-saved-objects-base-server-internal", + "@kbn/core-elasticsearch-server", ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 3ed262c0aa15..2a66c10a6509 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -1,5 +1,80 @@ { - "formats": {}, + "formats": { + "number": { + "currency": { + "style": "currency" + }, + "percent": { + "style": "percent" + } + }, + "date": { + "short": { + "month": "numeric", + "day": "numeric", + "year": "2-digit" + }, + "medium": { + "month": "short", + "day": "numeric", + "year": "numeric" + }, + "long": { + "month": "long", + "day": "numeric", + "year": "numeric" + }, + "full": { + "weekday": "long", + "month": "long", + "day": "numeric", + "year": "numeric" + } + }, + "time": { + "short": { + "hour": "numeric", + "minute": "numeric" + }, + "medium": { + "hour": "numeric", + "minute": "numeric", + "second": "numeric" + }, + "long": { + "hour": "numeric", + "minute": "numeric", + "second": "numeric", + "timeZoneName": "short" + }, + "full": { + "hour": "numeric", + "minute": "numeric", + "second": "numeric", + "timeZoneName": "short" + } + }, + "relative": { + "years": { + "style": "long" + }, + "months": { + "style": "long" + }, + "days": { + "style": "long" + }, + "hours": { + "style": "long" + }, + "minutes": { + "style": "long" + }, + "seconds": { + "style": "long" + } + } + }, "messages": { "advancedSettings.advancedSettingsLabel": "Paramètres avancés", "advancedSettings.featureCatalogueTitle": "Personnalisez votre expérience Kibana : modifiez le format de date, activez le mode sombre, et bien plus encore.", @@ -8,7 +83,7 @@ "aiAssistantManagementSelection.aiAssistantSelectionPage.obsAssistant.manageSettingsButtonLabel": "Gérer les paramètres", "aiAssistantManagementSelection.aiAssistantSelectionPage.observabilityAi.thisFeatureIsDisabledCallOutLabel": "Cette fonctionnalité est désactivée.", "aiAssistantManagementSelection.aiAssistantSelectionPage.observabilityLabel": "Assistant d'IA Elastic pour Observability", - "aiAssistantManagementSelection.aiAssistantSelectionPage.securityAi.thisFeatureIsDisabledCallOutLabel": "Cette fonctionnalité est désactivée. Elle peut être activée dans Espaces > Fonctionnalités.", + "aiAssistantManagementSelection.aiAssistantSelectionPage.securityAi.thisFeatureIsDisabledCallOutLabel": "Cette fonctionnalité est désactivée. Vous pouvez l'activer à partir de Espaces > Fonctionnalités.", "aiAssistantManagementSelection.aiAssistantSelectionPage.securityAssistant.documentationLinkDescription": "Pour en savoir plus, consultez notre {documentation}.", "aiAssistantManagementSelection.aiAssistantSelectionPage.securityAssistant.manageSettingsButtonLabel": "Gérer les paramètres", "aiAssistantManagementSelection.aiAssistantSelectionPage.securityLabel": "Assistant d'IA Elastic pour Security", @@ -27,6 +102,41 @@ "aiAssistantManagementSelection.preferredAIAssistantTypeSettingValueNever": "Nulle part", "aiAssistantManagementSelection.preferredAIAssistantTypeSettingValueObservability": "Partout", "alertingTypes.builtinActionGroups.recovered": "Récupéré", + "alertsGrouping.unit": "{totalCount, plural, =1 {alerte} other {alertes}}", + "alertsUIShared.actiActionsonNotifyWhen.forEachOption": "Pour chaque alerte", + "alertsUIShared.actiActionsonNotifyWhen.summaryOption": "Résumé des alertes", + "alertsUIShared.actionForm.actionGroupRecoveredMessage": "Récupéré", + "alertsUIShared.actionVariables.alertActionGroupLabel": "Groupe d'actions de l'alerte ayant programmé les actions pour la règle.", + "alertsUIShared.actionVariables.alertActionGroupNameLabel": "Nom lisible par l'utilisateur du groupe d'actions de l'alerte ayant programmé les actions pour la règle.", + "alertsUIShared.actionVariables.alertConsecutiveMatchesLabel": "Le nombre de courses consécutives qui remplissent les conditions de la règle.", + "alertsUIShared.actionVariables.alertFlappingLabel": "Indicateur sur l'alerte spécifiant si le statut de l'alerte change fréquemment.", + "alertsUIShared.actionVariables.alertIdLabel": "ID de l'alerte ayant programmé les actions pour la règle.", + "alertsUIShared.actionVariables.alertUuidLabel": "UUID de l'alerte ayant programmé les actions pour la règle.", + "alertsUIShared.actionVariables.allAlertsCountLabel": "Décompte de toutes les alertes.", + "alertsUIShared.actionVariables.allAlertsDataLabel": "Tableau d'objets pour toutes les alertes.", + "alertsUIShared.actionVariables.dateLabel": "Date à laquelle la règle a programmé l'action.", + "alertsUIShared.actionVariables.kibanaBaseUrlLabel": "Valeur server.publicBaseUrl configurée ou chaîne vide si elle n'est pas configurée.", + "alertsUIShared.actionVariables.legacyAlertActionGroupLabel": "Cet élément a été déclassé au profit de {variable}.", + "alertsUIShared.actionVariables.legacyAlertActionGroupNameLabel": "Cet élément a été déclassé au profit de {variable}.", + "alertsUIShared.actionVariables.legacyAlertIdLabel": "Cet élément a été déclassé au profit de {variable}.", + "alertsUIShared.actionVariables.legacyAlertInstanceIdLabel": "Cet élément a été déclassé au profit de {variable}.", + "alertsUIShared.actionVariables.legacyAlertNameLabel": "Cet élément a été déclassé au profit de {variable}.", + "alertsUIShared.actionVariables.legacyParamsLabel": "Cet élément a été déclassé au profit de {variable}.", + "alertsUIShared.actionVariables.legacySpaceIdLabel": "Cet élément a été déclassé au profit de {variable}.", + "alertsUIShared.actionVariables.legacyTagsLabel": "Cet élément a été déclassé au profit de {variable}.", + "alertsUIShared.actionVariables.newAlertsCountLabel": "Décompte des nouvelles alertes.", + "alertsUIShared.actionVariables.newAlertsDataLabel": "Tableau d'objets pour les nouvelles alertes.", + "alertsUIShared.actionVariables.ongoingAlertsCountLabel": "Décompte des alertes en cours.", + "alertsUIShared.actionVariables.ongoingAlertsDataLabel": "Tableau d'objets pour les alertes en cours.", + "alertsUIShared.actionVariables.recoveredAlertsCountLabel": "Décompte des alertes récupérées.", + "alertsUIShared.actionVariables.recoveredAlertsDataLabel": "Tableau d'objets pour les alertes récupérées.", + "alertsUIShared.actionVariables.ruleIdLabel": "ID de la règle.", + "alertsUIShared.actionVariables.ruleNameLabel": "Nom de la règle.", + "alertsUIShared.actionVariables.ruleParamsLabel": "Les paramètres de la règle.", + "alertsUIShared.actionVariables.ruleSpaceIdLabel": "ID d'espace de la règle.", + "alertsUIShared.actionVariables.ruleTagsLabel": "Balises de la règle.", + "alertsUIShared.actionVariables.ruleTypeLabel": "Type de règle.", + "alertsUIShared.actionVariables.ruleUrlLabel": "L'URL d'accès à la règle qui a généré l'alerte. La chaîne sera vide si server.publicBaseUrl n'est pas configuré.", "alertsUIShared.alertFieldsTable.field": "Champ", "alertsUIShared.alertFieldsTable.filter.placeholder": "Filtre par Champ, Valeur ou Description...", "alertsUIShared.alertFieldsTable.value": "Valeur", @@ -34,6 +144,8 @@ "alertsUIShared.alertFilterControls.defaultControlDisplayNames.rule": "Règle", "alertsUIShared.alertFilterControls.defaultControlDisplayNames.status": "Statut", "alertsUIShared.alertFilterControls.defaultControlDisplayNames.tags": "Balises", + "alertsUIShared.checkActionTypeEnabled.actionTypeDisabledByConfigMessage": "Ce connecteur est désactivé par la configuration de Kibana.", + "alertsUIShared.checkActionTypeEnabled.actionTypeDisabledByLicenseMessage": "Ce connecteur requiert une licence {minimumLicenseRequired}.", "alertsUIShared.component.alertsSearchBar.placeholder": "Alertes de recherche (par exemple, kibana.alert.evaluation.threshold > 75)", "alertsUIShared.components.addMessageVariables.addRuleVariableTitle": "Ajouter une variable", "alertsUIShared.components.addMessageVariables.addVariablePopoverButton": "Ajouter une variable", @@ -54,10 +166,11 @@ "alertsUIShared.components.ruleTypeModal.noRuleTypesErrorTitle": "Aucun type de règles trouvé", "alertsUIShared.components.ruleTypeModal.searchPlaceholder": "Recherche", "alertsUIShared.components.ruleTypeModal.title": "Sélectionner le type de règle", + "alertsUIShared.disabledActionsWarningTitle": "Cette règle possède des actions qui sont désactivées", "alertsUIShared.filterGroup.contextMenu.reset": "Réinitialiser les contrôles", "alertsUIShared.filterGroup.contextMenu.resetTooltip": "Réinitialiser les contrôles aux paramètres d'usine", "alertsUIShared.filterGroup.filtersChangedBanner": "Les contrôles de filtre ont changé", - "alertsUIShared.filterGroup.filtersChangedTitle": "Les nouveaux contrôles de filtre de cette page sont différents de ceux que vous avez précédemment enregistrés. Vous pouvez enregistrer les modifications ou les ignorer.\n Si vous quittez cette fenêtre, ces modifications seront automatiquement ignorées", + "alertsUIShared.filterGroup.filtersChangedTitle": "Les nouveaux contrôles de filtre de cette page sont différents de ceux que vous avez précédemment enregistrés. Vous pouvez enregistrer les modifications ou les ignorer. Si vous quittez cette fenêtre, ces modifications seront automatiquement ignorées", "alertsUIShared.filterGroup.groupMenuTitle": "Menu de groupe de filtres", "alertsUIShared.filtersGroup.contextMenu.addControls": "Ajouter des contrôles", "alertsUIShared.filtersGroup.contextMenu.addControls.maxLimit": "Un maximum de 4 contrôles peut être ajouté.", @@ -68,8 +181,24 @@ "alertsUIShared.filtersGroup.discardChanges": "Abandonner les modifications", "alertsUIShared.filtersGroup.pendingChanges": "Enregistrer les modifications en attente", "alertsUIShared.filtersGroup.urlParam.arrayError": "Les paramètres d'URL du filtre de page doivent être un tableau", + "alertsUIShared.healthCheck.actionText": "En savoir plus.", + "alertsUIShared.healthCheck.alertsErrorText": "Pour créer une règle, vous devez activer les plug-ins d'alerting et d'actions.", + "alertsUIShared.healthCheck.alertsErrorTitle": "Vous devez activer Alerting et Actions", + "alertsUIShared.healthCheck.apiKeysAndEncryptionErrorText": "Vous devez activer les clés d'API et configurer une clé de chiffrement pour utiliser Alerting.", + "alertsUIShared.healthCheck.apiKeysDisabledErrorText": "Vous devez activer les clés d'API pour utiliser Alerting.", + "alertsUIShared.healthCheck.apiKeysDisabledErrorTitle": "Configuration supplémentaire requise", + "alertsUIShared.healthCheck.encryptionErrorText": "Vous devez configurer une clé de chiffrement pour utiliser Alerting.", + "alertsUIShared.healthCheck.encryptionErrorTitle": "Configuration supplémentaire requise", + "alertsUIShared.healthCheck.healthCheck.apiKeysAndEncryptionErrorTitle": "Configuration supplémentaire requise", + "alertsUIShared.hooks.useAlertDataView.fetchErrorMessage": "Impossible de charger la vue des données de l'alerte", + "alertsUIShared.hooks.useFindAlertsQuery.unableToFetchAlertsGroupingAggregations": "Impossible de récupérer les agrégations de groupement d'alertes", + "alertsUIShared.hooks.useFindAlertsQuery.unableToFindAlertsQueryMessage": "Impossible de trouver les alertes", "alertsUIShared.hooks.useLoadRuleTypesQuery.unableToLoadRuleTypesMessage": "Impossible de charger les types de règles", "alertsUIShared.hooks.useRuleAADFields.errorMessage": "Impossible de charger les champs d'alerte par type de règle", + "alertsUIShared.licenseCheck.actionTypeDisabledByConfigMessageTitle": "Cette fonctionnalité est désactivée par la configuration de Kibana.", + "alertsUIShared.licenseCheck.actionTypeDisabledByLicenseLinkTitle": "Afficher les options de licence", + "alertsUIShared.licenseCheck.actionTypeDisabledByLicenseMessageDescription": "Pour réactiver cette action, veuillez mettre à niveau votre licence.", + "alertsUIShared.licenseCheck.actionTypeDisabledByLicenseMessageTitle": "Cette fonctionnalité requiert une licence {minimumLicenseRequired}.", "alertsUIShared.maintenanceWindowCallout.fetchError": "La vérification visant à déterminer si les fenêtres de maintenance sont actives a échoué", "alertsUIShared.maintenanceWindowCallout.fetchErrorDescription": "Les notifications de règle sont arrêtées lorsque les fenêtres de maintenance sont en cours d'exécution.", "alertsUIShared.maintenanceWindowCallout.maintenanceWindowActive": "{activeWindowCount, plural, one {Une fenêtre de maintenance est} other {Des fenêtres de maintenance sont}} en cours d'exécution pour des règles de {categories}", @@ -89,20 +218,74 @@ "alertsUIShared.producerDisplayNames.slo": "SLO", "alertsUIShared.producerDisplayNames.stackAlerts": "Alertes de la suite", "alertsUIShared.producerDisplayNames.uptime": "Synthetics et Uptime", - "alertsUIShared.ruleForm.error.belowMinimumAlertDelayText": "Le délai d’alerte doit être supérieur à 1.", + "alertsUIShared.ruleActionsAlertsFilter.ActionAlertsFilterQueryPlaceholder": "Filtrer les alertes à l'aide de la syntaxe KQL", + "alertsUIShared.ruleActionsAlertsFilter.ActionAlertsFilterQueryToggleLabel": "Si l'alerte correspond à une requête", + "alertsUIShared.ruleActionsItem.actionErrorToolTip": "L’action contient des erreurs.", + "alertsUIShared.ruleActionsItem.actionUnableToLoadConnectorTitle": "Créez un connecteur et réessayez. Si vous ne parvenez pas à créer un connecteur, contactez votre administrateur système.", + "alertsUIShared.ruleActionsItem.actionUseAadTemplateFieldsLabel": "Utiliser les champs de modèle de l'index des alertes", + "alertsUIShared.ruleActionsItem.actionWarningsTitle": "1 avertissement", + "alertsUIShared.ruleActionsItem.existingAlertActionTypeEditTitle": "{actionConnectorName}", + "alertsUIShared.ruleActionsItem.runWhenGroupTitle": "Exécuter lorsque {groupName}", + "alertsUIShared.ruleActionsItem.summaryGroupTitle": "Résumé des alertes", + "alertsUIShared.ruleActionsNotifyWhen.actionFrequencyLabel": "Fréquence d'action", + "alertsUIShared.ruleActionsNotifyWhen.frequencyNotifyWhen.label": "Exécuter chaque", + "alertsUIShared.ruleActionsNotifyWhen.notifyWhenThrottleWarning": "Les intervalles d'action personnalisés ne peuvent pas être plus courts que l'intervalle de vérification de la règle", + "alertsUIShared.ruleActionsNotifyWhen.onActionGroupChange.description": "Actions exécutées si le statut de l'alerte change.", + "alertsUIShared.ruleActionsNotifyWhen.onActionGroupChange.display": "Lors de changements de statut", + "alertsUIShared.ruleActionsNotifyWhen.onActionGroupChange.label": "Lors de changements de statut", + "alertsUIShared.ruleActionsNotifyWhen.onActiveAlert.description": "Les actions sont exécutées si les conditions de règle sont remplies.", + "alertsUIShared.ruleActionsNotifyWhen.onActiveAlert.display": "Selon les intervalles de vérification", + "alertsUIShared.ruleActionsNotifyWhen.onActiveAlert.label": "Selon les intervalles de vérification", + "alertsUIShared.ruleActionsNotifyWhen.onThrottleInterval.description": "Les actions sont exécutées si les conditions de règle sont remplies.", + "alertsUIShared.ruleActionsNotifyWhen.onThrottleInterval.display": "Selon des intervalles d'action personnalisés", + "alertsUIShared.ruleActionsNotifyWhen.onThrottleInterval.label": "Selon des intervalles d'action personnalisés", + "alertsUIShared.ruleActionsNotifyWhen.summaryOrRulePerSelectRoleDescription": "Sélection du type de fréquence d'action", + "alertsUIShared.ruleActionsSetting.actionGroupNotSupported": "{actionGroupName} (non pris en charge actuellement)", + "alertsUIShared.ruleActionsSetting.actionGroupRunWhen": "Exécuter quand", + "alertsUIShared.ruleActionsSystemActionsItem.deleteActionAriaLabel": "supprimer l'action", + "alertsUIShared.ruleForm.actionsForm.publicBaseUrl": "server.publicBaseUrl n'est pas défini. Les URL générées seront relatives ou vides.", + "alertsUIShared.ruleForm.actionsForm.requiredFilterQuery": "Une requête personnalisée est requise.", + "alertsUIShared.ruleForm.actionTypeModalEmptyText": "Essayez une autre recherche ou modifiez vos paramètres de filtrage.", + "alertsUIShared.ruleForm.actionTypeModalEmptyTitle": "Aucun connecteur trouvé", + "alertsUIShared.ruleForm.actionTypeModalFilterAll": "Tous", + "alertsUIShared.ruleForm.actionTypeModalTitle": "Sélectionner un connecteur", + "alertsUIShared.ruleForm.circuitBreakerHideFullErrorText": "Masquer l'erreur en intégralité", + "alertsUIShared.ruleForm.circuitBreakerSeeFullErrorText": "Afficher l'erreur en intégralité", + "alertsUIShared.ruleForm.confirmRuleSaveCancelButtonText": "Annuler", + "alertsUIShared.ruleForm.confirmRuleSaveConfirmButtonText": "Enregistrer la règle", + "alertsUIShared.ruleForm.confirmRuleSaveMessageText": "Vous pouvez ajouter une action à tout moment.", + "alertsUIShared.ruleForm.confirmRuleSaveTitle": "Enregistrer la règle ne contenant aucune action ?", + "alertsUIShared.ruleForm.createErrorText": "Impossible de créer une règle.", + "alertsUIShared.ruleForm.createSuccessText": "Création de la règle \"{ruleName}\" effectuée", + "alertsUIShared.ruleForm.editErrorText": "Impossible de mettre à jour la règle.", + "alertsUIShared.ruleForm.editSuccessText": "Mise à jour de \"{ruleName}\" effectuée", + "alertsUIShared.ruleForm.error.belowMinimumAlertDelayText": "Le délai d'alerte doit être supérieur ou égal à 1.", "alertsUIShared.ruleForm.error.belowMinimumText": "L'intervalle doit être au minimum de {minimum}.", "alertsUIShared.ruleForm.error.requiredConsumerText": "La portée est requise.", "alertsUIShared.ruleForm.error.requiredIntervalText": "L'intervalle de vérification est requis.", "alertsUIShared.ruleForm.error.requiredNameText": "Le nom est requis.", "alertsUIShared.ruleForm.error.requiredRuleTypeIdText": "Le type de règle est requis.", "alertsUIShared.ruleForm.intervalWarningText": "Des intervalles inférieurs à {minimum} ne sont pas recommandés pour des raisons de performances.", + "alertsUIShared.ruleForm.modalSearchClearFiltersText": "Effacer les filtres", + "alertsUIShared.ruleForm.modalSearchPlaceholder": "Recherche", + "alertsUIShared.ruleForm.returnTitle": "Renvoyer", + "alertsUIShared.ruleForm.routeParamsErrorText": "Une erreur s'est produite lors du chargement du formulaire de la règle. Veuillez vérifier que le chemin est correct.", + "alertsUIShared.ruleForm.routeParamsErrorTitle": "Impossible de charger le formulaire de règle", "alertsUIShared.ruleForm.ruleActions.addActionText": "Ajouter une action", + "alertsUIShared.ruleForm.ruleActionsAlertsFilterTimeframeTimezoneLabel": "Fuseau horaire", + "alertsUIShared.ruleForm.ruleActionsAlertsFilterTimeframeToggleLabel": "Si l'alerte est générée pendant l'intervalle de temps", + "alertsUIShared.ruleForm.ruleActionsAlertsFilterTimeframeWeekdays": "Jours de la semaine", + "alertsUIShared.ruleForm.ruleActionsNoPermissionDescription": "Pour modifier les règles, vous devez avoir un accès en lecture aux actions et aux connecteurs.", + "alertsUIShared.ruleForm.ruleActionsNoPermissionTitle": "Privilèges manquants pour les actions et les connecteurs", + "alertsUIShared.ruleForm.ruleActionsTitle": "Actions", "alertsUIShared.ruleForm.ruleAlertDelay.alertDelayHelpText": "Une alerte n'est déclenchée que si le nombre spécifié d'exécutions consécutives remplit les conditions de la règle.", "alertsUIShared.ruleForm.ruleAlertDelay.alertDelayTitlePrefix": "Après une alerte", "alertsUIShared.ruleForm.ruleAlertDelay.alertDelayTitleSuffix": "correspondances consécutives", "alertsUIShared.ruleForm.ruleDefinition.advancedOptionsTitle": "Options avancées", "alertsUIShared.ruleForm.ruleDefinition.alertDelayDescription": "Définir le nombre d’exécutions consécutives pour lesquelles cette règle doit répondre aux conditions d'alerte avant qu'une alerte ne se déclenche", "alertsUIShared.ruleForm.ruleDefinition.alertDelayTitle": "Délai d'alerte", + "alertsUIShared.ruleForm.ruleDefinition.alertFlappingDetectionDescription": "Détectez les alertes qui passent rapidement de l'état actif à l'état récupéré et réduisez le bruit non souhaité de ces alertes instables", + "alertsUIShared.ruleForm.ruleDefinition.alertFlappingDetectionTitle": "Détection de bagotement d'alerte", "alertsUIShared.ruleForm.ruleDefinition.docLinkTitle": "Afficher la documentation", "alertsUIShared.ruleForm.ruleDefinition.loadingRuleTypeParamsTitle": "Chargement des paramètres de types de règles", "alertsUIShared.ruleForm.ruleDefinition.scheduleDescriptionText": "Définir la fréquence de vérification des conditions de l'alerte", @@ -110,10 +293,18 @@ "alertsUIShared.ruleForm.ruleDefinition.scheduleTooltipText": "Les vérifications sont mises en file d'attente ; elles seront exécutées au plus près de la valeur définie, en fonction de la capacité.", "alertsUIShared.ruleForm.ruleDefinition.scopeDescriptionText": "Sélectionnez les applications auxquelles associer le privilège de rôle correspondant", "alertsUIShared.ruleForm.ruleDefinition.scopeTitle": "Portée de la règle", + "alertsUIShared.ruleForm.ruleDefinitionTitle": "Définition de la règle", "alertsUIShared.ruleForm.ruleDetails.description": "Définissez un nom et des balises pour votre règle.", + "alertsUIShared.ruleForm.ruleDetails.ruleNameInputButtonAriaLabel": "Enregistrer le nom de la règle", "alertsUIShared.ruleForm.ruleDetails.ruleNameInputTitle": "Nom de règle", "alertsUIShared.ruleForm.ruleDetails.ruleTagsInputTitle": "Balises", + "alertsUIShared.ruleForm.ruleDetails.ruleTagsPlaceholder": "Ajouter des balises", "alertsUIShared.ruleForm.ruleDetails.title": "Nom et balises de la règle", + "alertsUIShared.ruleForm.ruleDetailsTitle": "Détails de la règle", + "alertsUIShared.ruleForm.ruleFormCancelModalCancel": "Annuler", + "alertsUIShared.ruleForm.ruleFormCancelModalConfirm": "Abandonner les modifications", + "alertsUIShared.ruleForm.ruleFormCancelModalDescription": "Vous ne pouvez pas récupérer de modifications non enregistrées.", + "alertsUIShared.ruleForm.ruleFormCancelModalTitle": "Abandonner les modifications non enregistrées apportées à la règle ?", "alertsUIShared.ruleForm.ruleFormConsumerSelection.apm": "APM et expérience utilisateur", "alertsUIShared.ruleForm.ruleFormConsumerSelection.consumerSelectComboBoxTitle": "Sélectionner une portée", "alertsUIShared.ruleForm.ruleFormConsumerSelection.consumerSelectTitle": "Visibilité du rôle", @@ -122,7 +313,53 @@ "alertsUIShared.ruleForm.ruleFormConsumerSelection.slo": "SLO", "alertsUIShared.ruleForm.ruleFormConsumerSelection.stackAlerts": "Règles de la Suite Elastic", "alertsUIShared.ruleForm.ruleFormConsumerSelection.uptime": "Synthetics et Uptime", + "alertsUIShared.ruleForm.ruleNotFoundErrorText": "Une erreur s'est produite lors du chargement de la règle. Veuillez vous assurer que la règle existe et que vous y avez accès.", + "alertsUIShared.ruleForm.ruleNotFoundErrorTitle": "Impossible de charger la règle", + "alertsUIShared.ruleForm.rulePage.ruleNameAriaLabelText": "Modifier le nom de la règle", + "alertsUIShared.ruleForm.rulePageFooter.cancelText": "Annuler", + "alertsUIShared.ruleForm.rulePageFooter.createText": "Créer une règle", + "alertsUIShared.ruleForm.rulePageFooter.saveText": "Enregistrer la règle", + "alertsUIShared.ruleForm.rulePageFooter.showRequestText": "Afficher la requête", "alertsUIShared.ruleForm.ruleSchedule.scheduleTitlePrefix": "Chaque", + "alertsUIShared.ruleForm.ruleTypeNotFoundErrorText": "Une erreur s'est produite lors du chargement du type de règle. Veuillez vous assurer que vous avez accès au type de règle sélectionné.", + "alertsUIShared.ruleForm.ruleTypeNotFoundErrorTitle": "Impossible de charger le type de règle", + "alertsUIShared.ruleForm.showRequestModal.headerTitle": "{requestType} requête de règle d'alerte", + "alertsUIShared.ruleForm.showRequestModal.headerTitleCreate": "Créer", + "alertsUIShared.ruleForm.showRequestModal.headerTitleEdit": "Modifier", + "alertsUIShared.ruleForm.showRequestModal.somethingWentWrongDescription": "Désolé, un problème est survenu.", + "alertsUIShared.ruleForm.showRequestModal.subheadingTitle": "La requête Kibana va {requestType} cette règle.", + "alertsUIShared.ruleForm.showRequestModal.subheadingTitleCreate": "créer", + "alertsUIShared.ruleForm.showRequestModal.subheadingTitleEdit": "modifier", + "alertsUIShared.ruleSettingsFlappingForm.flappingExternalLinkLabel": "Qu'est-ce que c'est ?", + "alertsUIShared.ruleSettingsFlappingForm.flappingLabel": "Détection des éléments instables", + "alertsUIShared.ruleSettingsFlappingForm.flappingOffContentRules": "Règles", + "alertsUIShared.ruleSettingsFlappingForm.flappingOffContentSettings": "Paramètres", + "alertsUIShared.ruleSettingsFlappingForm.flappingOffPopoverContent": "Accédez à {rules} > {settings} pour activer la détection d'instabilité pour l'ensemble des règles d'un espace. Vous pouvez ensuite personnaliser la période d'analyse et les valeurs seuils de chaque règle.", + "alertsUIShared.ruleSettingsFlappingForm.flappingOverrideConfiguration": "Personnaliser la configuration", + "alertsUIShared.ruleSettingsFlappingForm.offLabel": "DÉSACTIVÉ", + "alertsUIShared.ruleSettingsFlappingForm.onLabel": "ACTIVÉ", + "alertsUIShared.ruleSettingsFlappingForm.overrideLabel": "Personnalisé", + "alertsUIShared.ruleSettingsFlappingInputsProps.lookBackWindowHelp": "Nombre minimal d'exécutions pour lesquelles le seuil doit être atteint.", + "alertsUIShared.ruleSettingsFlappingInputsProps.lookBackWindowLabel": "Fenêtre d'historique d'exécution de la règle", + "alertsUIShared.ruleSettingsFlappingInputsProps.statusChangeThresholdHelp": "Nombre minimal de fois où une alerte doit changer d'état dans la fenêtre d'historique.", + "alertsUIShared.ruleSettingsFlappingInputsProps.statusChangeThresholdLabel": "Seuil de modification du statut d'alerte", + "alertsUIShared.ruleSettingsFlappingMessage.flappingOffMessage": "La détection de bagotement d'alerte est désactivée. Les alertes seront générées en fonction de l'intervalle de la règle, ce qui peut entraîner des volumes d'alertes plus importants.", + "alertsUIShared.ruleSettingsFlappingMessage.flappingSettingsDescription": "Cette règle détecte qu'une alerte est instable si son statut change au moins {statusChangeThreshold} au cours des derniers/dernières {lookBackWindow}.", + "alertsUIShared.ruleSettingsFlappingMessage.lookBackWindowLabelRuleRuns": "{amount, number} règle {amount, plural, one {exécute} other {exécutent}}", + "alertsUIShared.ruleSettingsFlappingMessage.spaceFlappingSettingsDescription": "L'ensemble des règles (de cet espace) détecte qu'une alerte est instable lorsque son statut change au moins {statusChangeThreshold} au cours des derniers/dernières {lookBackWindow}.", + "alertsUIShared.ruleSettingsFlappingMessage.statusChangeThresholdTimes": "{amount, number} {amount, plural, other {fois}}", + "alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingOffContentRules": "Règles", + "alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingOffContentSettings": "Paramètres", + "alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingTitlePopover1": "Lorsque la {flappingDetection} est activée, les alertes qui passent rapidement de l'état actif à l'état récupéré sont identifiées comme \"instables\" et les notifications sont réduites.", + "alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingTitlePopover2": "Le statut {alertStatus} définit une période (nombre minimum d'exécutions) utilisée dans l'algorithme de détection.", + "alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingTitlePopover3": "Le paramètre {lookBack} indique le nombre minimum de fois que les alertes doivent changer d'état au cours de la période seuil pour être considérées comme des alertes instables.", + "alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingTitlePopover4": "Accédez à {rules} > {settings} pour activer la détection d'instabilité pour l'ensemble des règles d'un espace. Vous pouvez ensuite personnaliser la période d'analyse et les valeurs seuils de chaque règle.", + "alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingTitlePopoverAlertStatus": "seuil de modification du statut d'alerte", + "alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingTitlePopoverFlappingDetection": "détection des éléments instables", + "alertsUIShared.ruleSettingsFlappingTitleTooltip.flappingTitlePopoverLookBack": "fenêtre d'historique d'exécution de la règle", + "alertsUIShared.ruleSettingsFlappingTitleTooltip.tooltipTitle": "Détection de bagotement d'alerte", + "alertsUIShared.technicalPreviewBadgeDescription": "Cette fonctionnalité est en version d'évaluation technique et pourra être modifiée ou retirée complètement dans une future version. Elastic s'efforcera de corriger tout problème, mais les fonctionnalités des versions d'évaluation technique ne sont pas soumises aux SLA de support des fonctionnalités officielles en disponibilité générale.", + "alertsUIShared.technicalPreviewBadgeLabel": "Version d'évaluation technique", "alertsUIShared.timeUnits.dayLabel": "{timeValue, plural, one {jour} other {jours}}", "alertsUIShared.timeUnits.hourLabel": "{timeValue, plural, one {heure} other {heures}}", "alertsUIShared.timeUnits.minuteLabel": "{timeValue, plural, one {minute} other {minutes}}", @@ -143,6 +380,11 @@ "autocomplete.seeDocumentation": "Consultez la documentation", "autocomplete.selectField": "Veuillez d'abord sélectionner un champ...", "autocomplete.showValueListModal": "Afficher la liste de valeurs", + "avcBanner.body": "Elastic Security passe avec brio le test de protection contre les malwares réalisé par AV-Comparatives", + "avcBanner.readTheBlog.link": "Lire le blog", + "avcBanner.title": "Protection à 100 % sans aucun faux positif.", + "bfetch.advancedSettings.disableBfetchCompressionDeprecation": "Ce paramètre est déclassé et sera supprimé dans la version 9.0 de Kibana.", + "bfetch.advancedSettings.disableBfetchDeprecation": "Ce paramètre est déclassé et sera supprimé dans la version 9.0 de Kibana.", "bfetch.disableBfetch": "Désactiver la mise en lots de requêtes", "bfetch.disableBfetchCompression": "Désactiver la compression par lots", "bfetch.disableBfetchCompressionDesc": "Vous pouvez désactiver la compression par lots. Cela permet de déboguer des requêtes individuelles, mais augmente la taille des réponses.", @@ -246,7 +488,7 @@ "cloud.deploymentDetails.modal.closeButtonLabel": "Fermer", "cloud.deploymentDetails.modal.learnMoreButtonLabel": "En savoir plus", "coloring.colorMapping.assignments.autoAssignedTermAriaLabel": "Cette couleur sera automatiquement affectée au premier terme qui ne correspond pas à toutes les autres affectations", - "coloring.colorMapping.assignments.autoAssignedTermPlaceholder": "Affecté automatiquement", + "coloring.colorMapping.assignments.autoAssignedTermPlaceholder": "Terme d'affectation automatique", "coloring.colorMapping.assignments.deleteAssignmentButtonLabel": "Supprimer cette affectation", "coloring.colorMapping.assignments.duplicateCategoryWarning": "Une autre couleur a déjà été affectée à cette catégorie. Seule la première affectation correspondante sera utilisée.", "coloring.colorMapping.colorChangesModal.categoricalModeDescription": "Basculer en mode de catégorie conduira à l'abandon de toutes vos modifications de couleurs personnalisées", @@ -277,7 +519,7 @@ "coloring.colorMapping.container.mapCurrentValuesButtonLabel": "Ajouter tous les termes non affectés", "coloring.colorMapping.container.mappingAssignmentHeader": "Affectations de couleurs", "coloring.colorMapping.container.mapValueButtonLabel": "Ajouter tous les termes non affectés", - "coloring.colorMapping.container.mapValuesPromptDescription.mapValuesPromptDetail": "Ajoutez de nouvelles affectations pour commencer à associer des termes de vos données à des couleurs spécifiques.", + "coloring.colorMapping.container.mapValuesPromptDescription.mapValuesPromptDetail": "Ajoutez une nouvelle affectation pour associer manuellement des termes à des couleurs spécifiées.", "coloring.colorMapping.container.OpenAdditionalActionsButtonLabel": "Ouvrir les actions d'affectation supplémentaires", "coloring.colorMapping.container.unassignedTermsMode.ReuseColorsLabel": "Palette de couleurs", "coloring.colorMapping.container.unassignedTermsMode.ReuseGradientLabel": "Gradient", @@ -324,10 +566,14 @@ "console.autocompleteSuggestions.endpointLabel": "point de terminaison", "console.autocompleteSuggestions.methodLabel": "méthode", "console.autocompleteSuggestions.paramLabel": "param", + "console.closeFullscreenButton": "Fermer l'affichage pleine page", "console.consoleDisplayName": "Console", "console.consoleMenu.copyAsCurlFailedMessage": "Impossible de copier la requête en tant que cURL", "console.consoleMenu.copyAsCurlMessage": "Requête copiée en tant que cURL", - "console.deprecations.enabled.manualStepOneMessage": "Ouvrez le fichier de configuration kibana.yml.", + "console.consoleMenu.copyAsFailedMessage": "{requestsCount, plural, one {Une requête n'a pas pu être copiée} other {Plusieurs requêtes n'ont pas pu être copiées}} dans le presse-papiers", + "console.consoleMenu.copyAsSuccessMessage": "{requestsCount, plural, one {Une requête copiée} other {Plusieurs requêtes copiées}} dans le presse-papiers en tant que {language}", + "console.consoleMenu.missingDocumentationPage": "La page de documentation n'est pas encore disponible pour cette API.", + "console.deprecations.enabled.manualStepOneMessage": "Ouvrir le fichier de configuration kibana.yml.", "console.deprecations.enabled.manualStepTwoMessage": "Remplacez le paramètre \"console.enabled\" par \"console.ui.enabled\".", "console.deprecations.enabledMessage": "Pour empêcher les utilisateurs d'accéder à l'interface utilisateur de la console, utilisez le paramètre \"console.ui.enabled\" au lieu de \"console.enabled\".", "console.deprecations.enabledTitle": "Le paramètre \"console.enabled\" est déclassé", @@ -343,12 +589,39 @@ "console.deprecations.proxyFilterTitle": "Le paramètre \"console.proxyFilter\" est déclassé", "console.devToolsDescription": "Plutôt que l’interface cURL, utilisez une interface JSON pour exploiter vos données dans la console.", "console.devToolsTitle": "Interagir avec l'API Elasticsearch", + "console.editor.adjustPanelSizeAriaLabel": "Utilisez les flèches gauche et droite pour ajuster la taille des panneaux", + "console.editor.clearConsoleInputButton": "Effacer cette entrée", + "console.editor.clearConsoleOutputButton": "Effacer cette sortie", "console.embeddableConsole.customScreenReaderAnnouncement": "Il y a un nouveau repère de région nommé {landmarkHeading} avec des commandes de niveau de page à la fin du document.", - "console.embeddableConsole.landmarkHeading": "Console développeur", + "console.embeddableConsole.landmarkHeading": "Console développeur. Appuyez sur Entrée pour modifier. Une fois terminé, appuyez sur Échap pour arrêter la modification.", "console.embeddableConsole.title": "Console", - "console.historyPage.applyHistoryButtonLabel": "Appliquer", - "console.historyPage.clearHistoryButtonLabel": "Effacer", + "console.exportButton": "Exporter les requêtes", + "console.exportButtonTooltipLabel": "Exporter toutes les requêtes de la console vers un fichier TXT", + "console.helpButtonTooltipContent": "Aide", + "console.helpPopover.aboutConsoleButtonAriaLabel": "À propos du lien de la console", + "console.helpPopover.aboutConsoleLabel": "À propos de la console", + "console.helpPopover.aboutQueryDSLButtonAriaLabel": "À propos du lien QueryDSL", + "console.helpPopover.aboutQueryDSLLabel": "À propos de Query DSL", + "console.helpPopover.description": "La console est une interface utilisateur interactive qui vous permet d'appeler les API Elasticsearch et Kibana et d'afficher leurs réponses. Avec la syntaxe Query DSL et REST API, recherchez vos données, gérez les paramètres et bien plus encore.", + "console.helpPopover.rerunTourButtonAriaLabel": "Bouton de réexécution de la présentation des fonctionnalités", + "console.helpPopover.rerunTourLabel": "Réexécution de la présentation des fonctionnalités", + "console.helpPopover.title": "Console Elastic", + "console.historyPage.addAndRunButtonLabel": "Ajouter et exécuter", + "console.historyPage.applyHistoryButtonLabel": "Ajouter", + "console.historyPage.clearHistoryButtonLabel": "Effacer l'ensemble de l'historique", + "console.historyPage.emptyPromptBody": "Ce panneau d'historique affichera toutes les requêtes passées que vous avez exécutées, cela vous permettra de les examiner et de les réutiliser.", + "console.historyPage.emptyPromptFooterLabel": "Envie d'en savoir plus ?", + "console.historyPage.emptyPromptFooterLink": "Lire la documentation de la console", + "console.historyPage.emptyPromptTitle": "Aucune requête pour le moment", + "console.historyPage.monaco.noHistoryTextMessage": "# Aucun historique à afficher", + "console.historyPage.pageDescription": "Revoyez et réutilisez vos requêtes antérieures", "console.historyPage.pageTitle": "Historique", + "console.importButtonLabel": "Importer les requêtes", + "console.importButtonTooltipLabel": "Importer des requêtes dans l'éditeur depuis un fichier", + "console.importConfirmModal.body": "L'importation de ce fichier remplacera toutes les requêtes actuelles dans l'éditeur.", + "console.importConfirmModal.cancelButton": "Annuler", + "console.importConfirmModal.confirmButton": "Importer et remplacer", + "console.importConfirmModal.title": "Importer et remplacer les requêtes ?", "console.keyboardCommandActionLabel.autoIndent": "Appliquer les indentations", "console.keyboardCommandActionLabel.moveToLine": "Déplacer le curseur sur une ligne", "console.keyboardCommandActionLabel.moveToNextRequestEdge": "Accéder au début ou à la fin de la requête suivante", @@ -358,34 +631,130 @@ "console.loadingError.buttonLabel": "Recharger la console", "console.loadingError.message": "Essayez de recharger pour obtenir les données les plus récentes.", "console.loadingError.title": "Impossible de charger la console", + "console.monaco.loadFromDataUnrecognizedUrlErrorMessage": "Seules les URL avec le domaine Elastic (www.elastic.co) peuvent être chargées dans la console.", + "console.monaco.loadFromDataUriErrorMessage": "Impossible de charger les données du paramètre de requête load_from dans l'URL", + "console.monaco.outputTextarea": "Outils de développement de la console - Sortie", + "console.monaco.requestOptions.autoIndentButtonLabel": "Retrait automatique", + "console.monaco.requestOptions.copyAsUrlButtonLabel": "Copier en tant que", + "console.monaco.requestOptions.openDocumentationButtonLabel": "Ouvrir la référence d'API", + "console.monaco.sendRequestButtonTooltipAriaLabel": "Cliquer pour envoyer la requête", + "console.monaco.sendRequestButtonTooltipContent": "Cliquer pour envoyer la requête", "console.notification.clearHistory": "Effacer l'historique", "console.notification.disableSavingToHistory": "Désactiver l'enregistrement", + "console.notification.error.failedToReadFile": "Impossible de lire le fichier sélectionné.", + "console.notification.error.fileImportNoContent": "Le fichier sélectionné ne semble pas avoir de contenu. Sélectionnez un autre fichier.", + "console.notification.error.fileTooBigMessage": "La taille du fichier dépasse la limite de 2 Mo.", + "console.notification.fileImportedSuccessfully": "Le fichier sélectionné a été importé avec succès.", + "console.notification.monaco.error.couldNotSaveRequestTitle": "Impossible d'enregistrer la requête dans l'historique de la console.", + "console.notification.monaco.error.historyQuotaReachedMessage": "L'historique des requêtes est arrivé à saturation. Effacez l'historique de la console ou désactivez l'enregistrement de nouvelles requêtes.", + "console.notification.monaco.error.nonSupportedRequest": "La requête sélectionnée n'est pas valide.", + "console.notification.monaco.error.noRequestSelectedTitle": "Aucune requête sélectionnée. Sélectionnez une requête en positionnant le curseur dessus.", + "console.notification.monaco.error.unknownErrorTitle": "Erreur de requête inconnue", + "console.openFullscreenButton": "Ouvrir cette console en affichage pleine page", + "console.outputEmptyState.description": "Lorsque vous exécutez une requête dans le panneau de saisie, la réponse de sortie s'affichera ici.", + "console.outputEmptyState.docsLink": "Lire la documentation de la Console", + "console.outputEmptyState.learnMore": "Envie d'en savoir plus ?", + "console.outputEmptyState.title": "Entrer une nouvelle requête", + "console.outputPanel.copyOutputButtonTooltipAriaLabel": "Cliquez pour copier dans le presse-papier", + "console.outputPanel.copyOutputButtonTooltipContent": "Cliquez pour copier dans le presse-papier", + "console.outputPanel.copyOutputToast": "Sortie sélectionnée copiée dans le presse-papiers", + "console.outputPanel.copyOutputToastFailedMessage": "Impossible de copier la sortie sélectionnée dans le presse-papiers", "console.pageHeading": "Console", "console.requestInProgressBadgeText": "Requête en cours", "console.requestOptions.autoIndentButtonLabel": "Appliquer les indentations", "console.requestOptions.copyAsUrlButtonLabel": "Copier la commande cURL", "console.requestOptions.openDocumentationButtonLabel": "Afficher la documentation", "console.requestOptionsButtonAriaLabel": "Options de requête", + "console.requestPanel.contextMenu.defaultSelectedLanguage": "Définir par défaut", + "console.requestPanel.contextMenu.languageSelectorModalCancel": "Annuler", + "console.requestPanel.contextMenu.languageSelectorModalCopy": "Copier le code", + "console.requestPanel.contextMenu.languageSelectorModalTitle": "Sélectionner une langue", "console.requestTimeElapasedBadgeTooltipContent": "Temps écoulé", + "console.settingsPage.autocompleteRefreshSettingsDescription": "La console actualise les suggestions de saisie semi-automatique en interrogeant Elasticsearch. Utilisez des actualisations moins fréquentes pour réduire les coûts de bande passante.", + "console.settingsPage.autocompleteRefreshSettingsLabel": "Actualisation de la saisie semi-automatique", + "console.settingsPage.autocompleteSettingsLabel": "Saisie semi-automatique", "console.settingsPage.dataStreamsLabelText": "Flux de données", - "console.settingsPage.enableAccessibilityOverlayLabel": "Activer la superposition d’accessibilité", - "console.settingsPage.enableKeyboardShortcutsLabel": "Activer les raccourcis clavier", + "console.settingsPage.displaySettingsLabel": "Affichage", + "console.settingsPage.enableAccessibilityOverlayLabel": "Superposition d’accessibilité", + "console.settingsPage.enableKeyboardShortcutsLabel": "Raccourcis clavier", "console.settingsPage.fieldsLabelText": "Champs", "console.settingsPage.fontSizeLabel": "Taille de la police", + "console.settingsPage.generalSettingsLabel": "Paramètres généraux", "console.settingsPage.indicesAndAliasesLabelText": "Index et alias", + "console.settingsPage.manualRefreshLabel": "Actualiser manuellement les suggestions de saisie semi-automatique", + "console.settingsPage.offLabel": "Désactivé", + "console.settingsPage.onLabel": "Activé", + "console.settingsPage.pageDescription": "Personnalisez la console en fonction de votre workflow.", "console.settingsPage.pageTitle": "Paramètres de la console", - "console.settingsPage.refreshButtonLabel": "Actualiser les suggestions de saisie semi-automatique", + "console.settingsPage.refreshButtonLabel": "Actualiser", "console.settingsPage.refreshingDataLabel": "Fréquence d'actualisation", "console.settingsPage.refreshInterval.everyHourTimeInterval": "Toutes les heures", "console.settingsPage.refreshInterval.everyNMinutesTimeInterval": "Toutes les {value} {value, plural, one {minute} other {minutes}}", "console.settingsPage.refreshInterval.onceTimeInterval": "Une fois, au chargement de la console", "console.settingsPage.saveRequestsToHistoryLabel": "Enregistrer les requêtes dans l'historique", "console.settingsPage.templatesLabelText": "Modèles", - "console.settingsPage.tripleQuotesMessage": "Utiliser des guillemets triples dans la sortie", + "console.settingsPage.tripleQuotesMessage": "Guillemets triples dans la sortie", + "console.settingsPage.wrapLongLinesLabel": "Formater les longues lignes", + "console.shortcutKeys.keyAltOption": "Alt/Option", + "console.shortcutKeys.keyCtrlCmd": "Ctrl/Cmd", + "console.shortcutKeys.keyDownArrow": "Flèche vers le bas", + "console.shortcutKeys.keyEnter": "Entrée", + "console.shortcutKeys.keyEsc": "Échap", + "console.shortcutKeys.keyI": "I", + "console.shortcutKeys.keyL": "L", + "console.shortcutKeys.keyO": "O", + "console.shortcutKeys.keyOption": "Option", + "console.shortcutKeys.keyShift": "Déplacer", + "console.shortcutKeys.keySlash": "/", + "console.shortcutKeys.keySpace": "Espace", + "console.shortcutKeys.keyTab": "Onglet", + "console.shortcutKeys.keyUpArrow": "Flèche vers le haut", + "console.shortcuts.alternativeKeysOrDivider": "ou", + "console.shortcuts.autocompleteShortcutsSubtitle": "Raccourcis du menu de saisie semi-automatique", + "console.shortcuts.navigationShortcutsSubtitle": "Raccourcis de navigation", + "console.shortcuts.requestShortcutsSubtitle": "Demander des raccourcis", + "console.shortcutsButtonAriaLabel": "Raccourcis clavier", + "console.topNav.configTabDescription": "Config", + "console.topNav.configTabLabel": "Config", "console.topNav.historyTabDescription": "Historique", "console.topNav.historyTabLabel": "Historique", - "console.variablesPage.addButtonLabel": "Ajouter", + "console.topNav.shellTabDescription": "Shell", + "console.topNav.shellTabLabel": "Shell", + "console.tour.completeTourButton": "Terminé", + "console.tour.configStepContent": "Ajustez les paramètres de votre console et créez des variables pour personnaliser votre workflow.", + "console.tour.configStepTitle": "Personnaliser votre boîte à outils", + "console.tour.editorStepContent": "Saisissez une requête dans ce volet d'entrée et consultez la réponse dans le volet de sortie adjacent. Pour en savoir plus, consultez la {queryDslDocs}.", + "console.tour.editorStepTitle": "Lancez-vous dans les requêtes", + "console.tour.filesStepContent": "Exportez facilement vos requêtes de console vers un fichier ou importez celles que vous avez enregistrées précédemment.", + "console.tour.filesStepTitle": "Gérer les fichiers de la console", + "console.tour.historyStepContent": "Le panneau d'historique conserve une trace de vos requêtes antérieures, ce qui facilite leur révision et leur réexécution.", + "console.tour.historyStepTitle": "Consulter les requêtes antérieures", + "console.tour.nextStepButton": "Suivant", + "console.tour.shellStepContent": "La console est une interface utilisateur interactive qui vous permet d'appeler les API Elasticsearch et Kibana et d'afficher leurs réponses. Utilisez la syntaxe Query DSL pour rechercher vos données, gérer les paramètres et bien plus encore.", + "console.tour.shellStepTitle": "Bienvenue dans la Console", + "console.tour.skipTourButton": "Ignorer la visite", + "console.variablesButton": "Variables", + "console.variablesPage.addButtonLabel": "Ajouter une variable", + "console.variablesPage.addNew.cancelButton": "Annuler", + "console.variablesPage.addNew.submitButton": "Enregistrer les modifications", + "console.variablesPage.addNewVariableTitle": "Ajouter une nouvelle variable", + "console.variablesPage.deleteModal.cancelButtonText": "Annuler", + "console.variablesPage.deleteModal.confirmButtonText": "Supprimer la variable", + "console.variablesPage.deleteModal.description": "La suppression d'une variable est une opération irréversible.", + "console.variablesPage.deleteModal.title": "Voulez-vous vraiment continuer ?", + "console.variablesPage.editVariableForm.title": "Modifier la variable", + "console.variablesPage.form.namePlaceholderLabel": "exampleName", + "console.variablesPage.form.valueFieldLabel": "Valeur", + "console.variablesPage.form.valuePlaceholderLabel": "exampleValue", + "console.variablesPage.form.valueRequiredLabel": "La valeur est requise", + "console.variablesPage.form.variableNameFieldLabel": "Nom de la variable", + "console.variablesPage.form.variableNameInvalidLabel": "Seuls les lettres, les chiffres et les traits de soulignement sont autorisés", + "console.variablesPage.form.variableNameRequiredLabel": "Ceci est un champ requis", + "console.variablesPage.pageDescription": "Définissez des paramètres fictifs réutilisables pour les valeurs dynamiques dans vos requêtes.", "console.variablesPage.pageTitle": "Variables", + "console.variablesPage.table.noItemsMessage": "Aucune variable n'a encore été ajoutée", + "console.variablesPage.variablesTable.columns.deleteButton": "Supprimer {variable}", + "console.variablesPage.variablesTable.columns.editButton": "Modifier {variable}", "console.variablesPage.variablesTable.columns.valueHeader": "Valeur", "console.variablesPage.variablesTable.columns.variableHeader": "Nom de la variable", "contentManagement.contentEditor.activity.createdByLabelText": "Créé par", @@ -402,8 +771,25 @@ "contentManagement.contentEditor.metadataForm.readOnlyToolTip": "Veuillez contacter votre administrateur pour modifier ces détails", "contentManagement.contentEditor.metadataForm.tagsLabel": "Balises", "contentManagement.contentEditor.saveButtonLabel": "Mettre à jour {entityName}", + "contentManagement.contentEditor.viewsStats.noViewsTip": "Les vues sont comptées chaque fois qu'un utilisateur ouvre un tableau de bord", + "contentManagement.contentEditor.viewsStats.noViewsTipAriaLabel": "Informations supplémentaires", + "contentManagement.contentEditor.viewsStats.viewsLabel": "Vues", + "contentManagement.contentEditor.viewsStats.viewsLastNDaysLabel": "Vues ({n} derniers jours)", + "contentManagement.contentEditor.viewsStats.weekOfLabel": "Semaine du {date}", + "contentManagement.favorites.addFavoriteError": "Erreur lors de l'ajout aux Éléments avec étoiles", + "contentManagement.favorites.defaultEntityName": "élément", + "contentManagement.favorites.defaultEntityNamePlural": "éléments", + "contentManagement.favorites.favoriteButtonLabel": "Ajouter aux Éléments avec étoiles", + "contentManagement.favorites.noFavoritesIllustrationAlt": "Aucune illustration d'élément avec étoiles", + "contentManagement.favorites.noFavoritesMessageBody": "Suivez vos {entityNamePlural} les plus importants en les ajoutant à votre liste **En vedette**. Cliquez sur l'**icône étoile** **{starIcon}** située à côté d'un nom {entityName} afin qu'il s'affiche dans cet onglet.", + "contentManagement.favorites.noFavoritesMessageHeading": "Vous n'avez ajouté d'étoile à aucun {entityNamePlural}", + "contentManagement.favorites.noMatchingFavoritesMessageHeading": "Aucun {entityNamePlural} comportant une étoile ne correspond à votre recherche", + "contentManagement.favorites.removeFavoriteError": "Erreur lors de la suppression des Éléments avec étoiles", + "contentManagement.favorites.unfavoriteButtonLabel": "Supprimer des Éléments avec étoiles", "contentManagement.inspector.metadataForm.unableToSaveDangerMessage": "Impossible d'enregistrer {entityName}", "contentManagement.tableList.actionsDisabledLabel": "Actions désactivées pour cet élément", + "contentManagement.tableList.contentEditor.activityLabel": "Activité", + "contentManagement.tableList.contentEditor.activityLabelHelpText": "Les données liées à l'activité sont générées automatiquement et ne peuvent pas être mises à jour.", "contentManagement.tableList.createdByColumnTitle": "Créateur", "contentManagement.tableList.lastUpdatedColumnTitle": "Dernière mise à jour", "contentManagement.tableList.listing.createNewItemButtonLabel": "Créer {entityName}", @@ -428,6 +814,10 @@ "contentManagement.tableList.listing.tableSortSelect.headerLabel": "Trier par", "contentManagement.tableList.listing.tableSortSelect.nameAscLabel": "Nom A-Z", "contentManagement.tableList.listing.tableSortSelect.nameDescLabel": "Nom Z-A", + "contentManagement.tableList.listing.tableSortSelect.recentlyAccessedLabel": "Récemment consulté", + "contentManagement.tableList.listing.tableSortSelect.recentlyAccessedTip": "Les informations récemment consultées sont stockées localement dans votre navigateur et ne sont visibles que par vous.", + "contentManagement.tableList.listing.tableSortSelect.recentlyAccessedTipAriaLabel": "Informations supplémentaires", + "contentManagement.tableList.listing.tableSortSelect.sortingOptionsAriaLabel": "Options de tri", "contentManagement.tableList.listing.tableSortSelect.updatedAtAscLabel": "Mise à jour la moins récente", "contentManagement.tableList.listing.tableSortSelect.updatedAtDescLabel": "Mise à jour récente", "contentManagement.tableList.listing.unableToDeleteDangerMessage": "Impossible de supprimer la/le/les {entityName}(s)", @@ -438,6 +828,8 @@ "contentManagement.tableList.listing.userFilter.noCreators": "Aucun créateur", "contentManagement.tableList.mainColumnName": "Nom, description, balises", "contentManagement.tableList.managedItemNoEdit": "Elastic gère cet objet. Clonez-le pour effectuer des modifications.", + "contentManagement.tableList.tabsFilter.allTabLabel": "Tous", + "contentManagement.tableList.tabsFilter.favoriteTabLabel": "Éléments avec étoiles", "contentManagement.tableList.tagBadge.buttonLabel": "Bouton de balise {tagName}.", "contentManagement.tableList.tagFilterPanel.clearSelectionButtonLabelLabel": "Effacer la sélection", "contentManagement.tableList.tagFilterPanel.doneButtonLabel": "Terminé", @@ -447,12 +839,17 @@ "contentManagement.userProfiles.managedAvatarTip.avatarLabel": "Géré", "contentManagement.userProfiles.managedAvatarTip.avatarTooltip": "Cette entité {entityName} est créée et gérée par Elastic. Clonez-le pour effectuer des modifications.", "contentManagement.userProfiles.managedAvatarTip.defaultEntityName": "objet", - "contentManagement.userProfiles.noCreatorTip": "Les créateurs sont assignés lors de la création des objets (version 8.14 et versions ultérieures)", - "contentManagement.userProfiles.noUpdaterTip": "Le champ Mis à jour par est défini lors de la mise à jour des objets (version 8.14 et versions ultérieures)", + "contentManagement.userProfiles.noCreatorTip": "Les créateurs sont assignés lors de la création des objets", + "contentManagement.userProfiles.noUpdaterTip": "Le champ Mis à jour par est défini lors de la mise à jour des objets", + "controls.blockingError": "Une erreur s'est produite lors du chargement de ce contrôle.", + "controls.controlFactoryRegistry.factoryAlreadyExistsError": "Une usine de contrôle pour le type : {key} est déjà enregistrée.", + "controls.controlFactoryRegistry.factoryNotFoundError": "Aucune usine de contrôle n'a été trouvée pour le type : {key}", "controls.controlGroup.ariaActions.moveControlButtonAction": "Déplacer le contrôle {controlTitle}", + "controls.controlGroup.displayName": "Contrôles", "controls.controlGroup.floatingActions.clearTitle": "Effacer", "controls.controlGroup.floatingActions.editTitle": "Modifier", "controls.controlGroup.floatingActions.removeTitle": "Supprimer", + "controls.controlGroup.manageControl": "Modifier les paramètres du contrôle", "controls.controlGroup.manageControl.cancelTitle": "Annuler", "controls.controlGroup.manageControl.controlTypeSettings.formGroupDescription": "Paramètres personnalisés pour votre contrôle {controlType}.", "controls.controlGroup.manageControl.controlTypeSettings.formGroupTitle": "Paramètres {controlType}", @@ -461,13 +858,11 @@ "controls.controlGroup.manageControl.dataSource.controlTypeErrorMessage.rangeSlider": "Les curseurs ne sont compatibles qu'avec les champs de numéros.", "controls.controlGroup.manageControl.dataSource.controlTypErrorMessage.noField": "Sélectionnez d'abord un champ.", "controls.controlGroup.manageControl.dataSource.controlTypesTitle": "Type de contrôle", + "controls.controlGroup.manageControl.dataSource.dataViewListErrorTitle": "Erreur lors du chargement des vues de données", "controls.controlGroup.manageControl.dataSource.dataViewTitle": "Vue de données", + "controls.controlGroup.manageControl.dataSource.fieldListErrorTitle": "Erreur lors du chargement de la liste des champs", "controls.controlGroup.manageControl.dataSource.fieldTitle": "Champ", - "controls.controlGroup.manageControl.dataSource.formGroupDescription": "Sélectionnez la vue de données et le champ pour lesquels vous voulez créer un contrôle.", - "controls.controlGroup.manageControl.dataSource.formGroupTitle": "Source de données", "controls.controlGroup.manageControl.dataSource.selectDataViewMessage": "Veuillez sélectionner une vue de données", - "controls.controlGroup.manageControl.displaySettings.formGroupDescription": "Changez la manière dont le contrôle apparaît sur votre tableau de bord.", - "controls.controlGroup.manageControl.displaySettings.formGroupTitle": "Paramètres d'affichage", "controls.controlGroup.manageControl.displaySettings.growSwitchTitle": "Augmenter la largeur en fonction de l'espace disponible", "controls.controlGroup.manageControl.displaySettings.titleInputTitle": "Étiquette", "controls.controlGroup.manageControl.displaySettings.widthInputTitle": "Largeur minimale", @@ -505,13 +900,14 @@ "controls.controlGroup.management.showApplySelections.tooltip": "Si cette option est désactivée, les sélections de contrôle ne seront appliquées qu'après avoir cliqué sur \"Appliquer\".", "controls.controlGroup.management.validate.title": "Valider les sélections utilisateur", "controls.controlGroup.management.validate.tooltip": "Mettez en évidence les sélections de contrôle qui n'aboutissent à aucune donnée.", + "controls.dataControl.fieldNotFound": "Impossible de localiser le champ : {fieldName}", "controls.frame.error.message": "Une erreur s'est produite. Voir plus", - "controls.optionsList.control.dateSeparator": "; ", + "controls.optionsList.control.dateSeparator": ";", "controls.optionsList.control.excludeExists": "NE PAS", "controls.optionsList.control.invalidSelectionWarningLabel": "{invalidSelectionCount} {invalidSelectionCount, plural, one {sélection ne renvoie} other {sélections ne renvoient}} aucun résultat.", "controls.optionsList.control.negate": "NON", "controls.optionsList.control.placeholder": "N'importe lequel", - "controls.optionsList.control.separator": ", ", + "controls.optionsList.control.separator": ",", "controls.optionsList.controlAndPopover.exists": "{negate, plural, one {Existe} other {Existent}}", "controls.optionsList.displayName": "Liste des options", "controls.optionsList.editor.additionalSettingsTitle": "Paramètres supplémentaires", @@ -549,6 +945,7 @@ "controls.optionsList.popover.loadingMore": "Chargement d'options supplémentaires...", "controls.optionsList.popover.prefixSearchPlaceholder": "Commence par...", "controls.optionsList.popover.selectedOptionsTitle": "Afficher uniquement les options sélectionnées", + "controls.optionsList.popover.selectionError": "Une erreur s'est produite lors de la création de votre sélection", "controls.optionsList.popover.selectionsEmpty": "Vous n'avez pas de sélections", "controls.optionsList.popover.sortBy.alphabetical": "Par ordre alphabétique", "controls.optionsList.popover.sortBy.date": "Par date", @@ -565,6 +962,7 @@ "controls.rangeSlider.control.invalidSelectionWarningLabel": "La plage sélectionnée n'a donné aucun résultat.", "controls.rangeSlider.editor.stepSizeTitle": "Taille de l'étape", "controls.rangeSlider.popover.noAvailableDataHelpText": "Il n'y a aucune donnée à afficher. Ajustez la plage temporelle et les filtres.", + "controls.rangeSliderControl.displayName": "Curseur de plage", "controls.timeSlider.nextLabel": "Fenêtre temporelle suivante", "controls.timeSlider.pauseLabel": "Pause", "controls.timeSlider.playButtonTooltip.disabled": "\"Appliquer automatiquement les sélections\" est désactivé dans les paramètres du contrôle.", @@ -572,11 +970,13 @@ "controls.timeSlider.previousLabel": "Fenêtre temporelle précédente", "controls.timeSlider.settings.pinStart": "Épingler le début", "controls.timeSlider.settings.unpinStart": "Désépingler le début", + "controls.timesliderControl.displayName": "Curseur temporel", "core.application.appContainer.loadingAriaLabel": "Chargement de l'application", "core.application.appContainer.plainSpinner.loadingAriaLabel": "Chargement de l'application", "core.application.appNotFound.pageDescription": "Aucune application détectée pour cette URL. Revenez en arrière ou sélectionnez une application dans le menu.", "core.application.appNotFound.title": "Application introuvable", "core.application.appRenderError.defaultTitle": "Erreur d'application", + "core.chrome.euiDevProviderWarning": "Les composants Kibana doivent être intégrés dans un fournisseur React Context pour obtenir l'ensemble des fonctionnalités et une prise en charge adéquate des thèmes. Voir {link}.", "core.chrome.legacyBrowserWarning": "Votre navigateur ne satisfait pas aux exigences de sécurité de Kibana.", "core.deprecations.deprecations.fetchFailed.manualStepOneMessage": "Vérifiez le message d'erreur dans les logs de serveur Kibana.", "core.deprecations.deprecations.fetchFailedMessage": "Impossible d'extraire les informations de déclassement pour le plug-in {domainId}.", @@ -620,7 +1020,9 @@ "core.euiCodeBlockCopy.copy": "Copier", "core.euiCodeBlockFullScreen.fullscreenCollapse": "Réduire", "core.euiCodeBlockFullScreen.fullscreenExpand": "Développer", + "core.euiCollapsedItemActions.allActions": "Toutes les actions, ligne {index}", "core.euiCollapsedItemActions.allActionsDisabled": "Les actions individuelles sont désactivées lorsque plusieurs lignes sont sélectionnées.", + "core.euiCollapsedItemActions.allActionsTooltip": "Toutes les actions", "core.euiCollapsedNavButton.ariaLabelButtonIcon": "{title}, menu de navigation rapide", "core.euiCollapsibleNavBeta.ariaLabel": "Menu du site", "core.euiCollapsibleNavButton.ariaLabelClose": "Fermer la navigation", @@ -642,6 +1044,7 @@ "core.euiColumnActions.moveLeft": "Déplacer vers la gauche", "core.euiColumnActions.moveRight": "Déplacer vers la droite", "core.euiColumnActions.sort": "Trier {schemaLabel}", + "core.euiColumnActions.unsort": "Ne pas trier {schemaLabel}", "core.euiColumnSelector.button": "Colonnes", "core.euiColumnSelector.dragHandleAriaLabel": "Faire glisser la poignée", "core.euiColumnSelector.hideAll": "Tout masquer", @@ -674,9 +1077,11 @@ "core.euiDataGrid.screenReaderNotice": "Cette cellule contient du contenu interactif.", "core.euiDataGridCell.expansionEnterPrompt": "Appuyez sur Entrée pour développer cette cellule.", "core.euiDataGridCell.focusTrapEnterPrompt": "Appuyez sur Entrée pour interagir avec le contenu de cette cellule.", + "core.euiDataGridCell.focusTrapExitPrompt": "Vous avez quitté le contenu de la cellule.", "core.euiDataGridCell.position": "{columnName}, colonne {columnIndex}, ligne {rowIndex}", "core.euiDataGridCellActions.expandButtonTitle": "Cliquez ou appuyez sur Entrée pour interagir avec le contenu de la cellule.", - "core.euiDataGridHeaderCell.actionsButtonAriaLabel": "{title}. Cliquez pour afficher les actions d'en-tête de colonne", + "core.euiDataGridHeaderCell.actionsButtonAriaLabel": "{title}. Cliquez pour afficher les actions d'en-tête de colonne.", + "core.euiDataGridHeaderCell.actionsEnterKeyInstructions": "Appuyez sur la touche Entrée pour afficher les actions de cette colonne", "core.euiDataGridHeaderCell.actionsPopoverScreenReaderText": "Pour naviguer dans la liste des actions de la colonne, appuyez sur la touche Tab ou sur les flèches vers le haut et vers le bas.", "core.euiDataGridHeaderCell.sortedByAscendingFirst": "Trié par {columnId}, ordre croissant", "core.euiDataGridHeaderCell.sortedByAscendingMultiple": ", puis par {columnId}, ordre croissant", @@ -709,19 +1114,23 @@ "core.euiDatePopoverContent.startDateLabel": "Date de début", "core.euiDisplaySelector.buttonText": "Options d'affichage", "core.euiDisplaySelector.densityLabel": "Densité", + "core.euiDisplaySelector.labelAuto": "Ajustement automatique", "core.euiDisplaySelector.labelCompact": "Compact", "core.euiDisplaySelector.labelExpanded": "Étendu", "core.euiDisplaySelector.labelNormal": "Normal", "core.euiDisplaySelector.resetButtonText": "Réinitialiser à la valeur par défaut", - "core.euiDisplaySelector.rowHeightLabel": "Sous-lignes par ligne", + "core.euiDisplaySelector.rowHeightLabel": "Hauteur de la ligne", "core.euiDualRange.sliderScreenReaderInstructions": "Vous êtes dans un curseur de plage personnalisé. Utilisez les flèches vers le haut et vers le bas pour modifier la valeur minimale. Appuyez sur Tabulation pour interagir avec la valeur maximale.", "core.euiErrorBoundary.error": "Erreur", - "core.euiExternalLinkIcon.newTarget.screenReaderOnlyText": "(s’ouvre dans un nouvel onglet ou une nouvelle fenêtre)", + "core.euiExternalLinkIcon.externalTarget.screenReaderOnlyText": "(externe)", + "core.euiExternalLinkIcon.newTarget.screenReaderOnlyText": "(externe, s'ouvre dans un nouvel onglet ou une nouvelle fenêtre)", "core.euiFieldPassword.maskPassword": "Masquer le mot de passe", "core.euiFieldPassword.showPassword": "Afficher le mot de passe en texte brut. Remarque : votre mot de passe sera visible à l'écran.", + "core.euiFieldSearch.clearSearchButtonLabel": "Effacer la recherche", "core.euiFilePicker.filesSelected": "{fileCount} fichiers sélectionnés", "core.euiFilePicker.promptText": "Sélectionner ou glisser-déposer un fichier", "core.euiFilePicker.removeSelected": "Supprimer", + "core.euiFilePicker.removeSelectedAriaLabel": "Supprimer les fichiers sélectionnés", "core.euiFilterButton.filterBadgeActiveAriaLabel": "{count} filtres actifs", "core.euiFilterButton.filterBadgeAvailableAriaLabel": "{count} filtres disponibles", "core.euiFlyout.screenReaderFixedHeaders": "Vous pouvez quand même continuer à parcourir les en-têtes de page à l'aide de la touche Tabulation en plus de la boîte de dialogue.", @@ -852,6 +1261,10 @@ "core.euiRecentlyUsed.legend": "Plages de dates récemment utilisées", "core.euiRefreshInterval.fullDescriptionOff": "L'actualisation est désactivée, intervalle défini sur {optionValue} {optionText}.", "core.euiRefreshInterval.fullDescriptionOn": "L'actualisation est activée, intervalle défini sur {optionValue} {optionText}.", + "core.euiRefreshInterval.toggleAriaLabel": "Basculer sur l'actualisation", + "core.euiRefreshInterval.toggleLabel": "Actualiser toutes les", + "core.euiRefreshInterval.unitsAriaLabel": "Unités d'intervalle d'actualisation", + "core.euiRefreshInterval.valueAriaLabel": "Valeur d'intervalle d'actualisation", "core.euiRelativeTab.dateInputError": "Doit être une plage valide", "core.euiRelativeTab.fullDescription": "L'unité peut être modifiée. Elle est actuellement définie sur {unit}.", "core.euiRelativeTab.numberInputError": "Doit être >= 0.", @@ -973,6 +1386,8 @@ "core.notifications.errorToast.closeModal": "Fermer", "core.notifications.globalToast.ariaLabel": "Liste de messages de notification", "core.notifications.unableUpdateUISettingNotificationMessageTitle": "Impossible de mettre à jour le paramètre de l'interface utilisateur", + "core.overlays.confirm.cancelButton": "Annuler", + "core.overlays.confirm.okButton": "Confirmer", "core.savedObjects.deprecations.unknownTypes.manualSteps.1": "Activez les plug-ins désactivés, puis redémarrez Kibana.", "core.savedObjects.deprecations.unknownTypes.manualSteps.2": "Si aucun plug-in n'est désactivé ou si leur activation ne résout pas le problème, supprimez les documents.", "core.savedObjects.deprecations.unknownTypes.message": "{objectCount, plural, one {# objet} other {# objets}} de type inconnu {objectCount, plural, one {a été trouvé} other {ont été trouvés}} dans les indices du système Kibana. La mise à niveau avec des types savedObject inconnus n'est plus compatible. Pour assurer la réussite des mises à niveau à l'avenir, réactivez les plug-ins ou supprimez ces documents dans les indices de Kibana", @@ -1012,7 +1427,7 @@ "core.ui_settings.params.darkMode.options.disabled": "Désactivé", "core.ui_settings.params.darkMode.options.enabled": "Activé", "core.ui_settings.params.darkMode.options.system": "Synchroniser avec le système", - "core.ui_settings.params.darkModeText": "Le thème de l'interface utilisateur que l'interface utilisateur de Kibana doit utiliser. La valeur \"activé\" ou \"désactivé\" permet d'activer ou de désactiver le thème sombre. Définissez sur \"système\" pour que le thème de l'interface utilisateur de Kibana suive le thème du système. Vous devez actualiser la page pour que ce paramètre s’applique.", + "core.ui_settings.params.darkModeText": "Le thème de l'interface utilisateur que l'interface utilisateur de Kibana doit utiliser. Réglez l'option sur \"Activé\" pour activer le thème sombre ou sur \"Désactivé\" pour le désactiver. Définissez l'option sur \"Synchroniser avec le système\" pour que le thème de l'interface utilisateur de Kibana suive le thème du système. Vous devez recharger la page pour que ce paramètre s'applique.", "core.ui_settings.params.darkModeTitle": "Mode sombre", "core.ui_settings.params.dateFormat.dayOfWeekText": "Le premier jour de la semaine", "core.ui_settings.params.dateFormat.dayOfWeekTitle": "Jour de la semaine", @@ -1034,15 +1449,15 @@ "core.ui_settings.params.hideAnnouncements": "Masquer les annonces", "core.ui_settings.params.hideAnnouncementsText": "Arrêtez d’afficher les messages et les visites guidées qui mettent en avant les nouvelles fonctionnalités.", "core.ui_settings.params.notifications.banner.markdownLinkText": "Markdown pris en charge", - "core.ui_settings.params.notifications.bannerLifetimeText": "La durée en millisecondes durant laquelle une notification de bannière s'affiche à l'écran. ", + "core.ui_settings.params.notifications.bannerLifetimeText": "La durée en millisecondes durant laquelle une notification de bannière s'affiche à l'écran.", "core.ui_settings.params.notifications.bannerLifetimeTitle": "Durée des notifications de bannière", "core.ui_settings.params.notifications.bannerText": "Une bannière personnalisée à des fins de notification temporaire de l’ensemble des utilisateurs. {markdownLink}.", "core.ui_settings.params.notifications.bannerTitle": "Notification de bannière personnalisée", - "core.ui_settings.params.notifications.errorLifetimeText": "La durée en millisecondes durant laquelle une notification d'erreur s'affiche à l'écran. ", + "core.ui_settings.params.notifications.errorLifetimeText": "La durée en millisecondes durant laquelle une notification d'erreur s'affiche à l'écran.", "core.ui_settings.params.notifications.errorLifetimeTitle": "Durée des notifications d'erreur", - "core.ui_settings.params.notifications.infoLifetimeText": "La durée en millisecondes durant laquelle une notification d'information s'affiche à l'écran. ", + "core.ui_settings.params.notifications.infoLifetimeText": "La durée en millisecondes durant laquelle une notification d'information s'affiche à l'écran.", "core.ui_settings.params.notifications.infoLifetimeTitle": "Durée des notifications d'information", - "core.ui_settings.params.notifications.warningLifetimeText": "La durée en millisecondes durant laquelle une notification d'avertissement s'affiche à l'écran. ", + "core.ui_settings.params.notifications.warningLifetimeText": "La durée en millisecondes durant laquelle une notification d'avertissement s'affiche à l'écran.", "core.ui_settings.params.notifications.warningLifetimeTitle": "Durée des notifications d'avertissement", "core.ui_settings.params.storeUrlText": "L'URL peut parfois devenir trop longue pour être gérée par certains navigateurs. Pour pallier ce problème, nous testons actuellement le stockage de certaines parties de l'URL dans le stockage de session. N’hésitez pas à nous faire part de vos commentaires.", "core.ui_settings.params.storeUrlTitle": "Stocker les URL dans le stockage de session", @@ -1089,7 +1504,9 @@ "core.ui.primaryNav.cloud.linkToProject": "Gérer le projet", "core.ui.primaryNav.cloud.projectLabel": "Projet", "core.ui.primaryNav.goToHome.ariaLabel": "Accéder à la page d’accueil", + "core.ui.primaryNav.header.toggleNavAriaLabel": "Activer/Désactiver la navigation principale", "core.ui.primaryNav.pinnedLinksAriaLabel": "Liens épinglés", + "core.ui.primaryNav.project.toggleNavAriaLabel": "Activer/Désactiver la navigation principale", "core.ui.primaryNav.screenReaderLabel": "Principale", "core.ui.primaryNavSection.screenReaderLabel": "Liens de navigation principale, {category}", "core.ui.publicBaseUrlWarning.configRecommendedDescription": "Dans un environnement de production, il est recommandé de configurer {configKey}.", @@ -1185,7 +1602,7 @@ "customIntegrationsPackage.create.configureIntegrationDescription.helper": "Elastic crée une intégration pour rationaliser la connexion de vos données de log dans la Suite Elastic.", "customIntegrationsPackage.create.dataset.helper": "Tout en minuscules, 100 caractères maximum, les caractères spéciaux seront remplacés par \"_\".", "customIntegrationsPackage.create.dataset.name": "Nom de l’ensemble de données", - "customIntegrationsPackage.create.dataset.name.tooltip": "Le nom de l'ensemble de données associé à cette intégration. Ceci fera partie du nom du flux de données Elasticsearch ", + "customIntegrationsPackage.create.dataset.name.tooltip": "Le nom de l'ensemble de données associé à cette intégration. Ceci fera partie du nom du flux de données Elasticsearch", "customIntegrationsPackage.create.dataset.name.tooltipPrefixMessage": "Ce nom aura pour préfixe {prefixValue}, par ex. {prefixedDatasetName}", "customIntegrationsPackage.create.dataset.placeholder": "Nommez votre intégration de l'ensemble de données", "customIntegrationsPackage.create.errorCallout.authorization.description": "Cet utilisateur ne dispose pas d'autorisations pour créer une intégration.", @@ -1209,9 +1626,6 @@ "dashboard.actions.toggleExpandPanelMenuItem.notExpandedDisplayName": "Maximiser", "dashboard.addPanel.newEmbeddableAddedSuccessMessageTitle": "{savedObjectName} a été ajouté.", "dashboard.addPanel.newEmbeddableWithNoTitleAddedSuccessMessageTitle": "Un panneau a été ajouté", - "dashboard.appLeaveConfirmModal.cancelButtonLabel": "Annuler", - "dashboard.appLeaveConfirmModal.unsavedChangesSubtitle": "Quitter Dashboard sans enregistrer ?", - "dashboard.appLeaveConfirmModal.unsavedChangesTitle": "Modifications non enregistrées", "dashboard.badge.readOnly.text": "Lecture seule", "dashboard.badge.readOnly.tooltip": "Impossible d'enregistrer les tableaux de bord", "dashboard.createConfirmModal.cancelButtonLabel": "Annuler", @@ -1231,6 +1645,7 @@ "dashboard.editingToolbar.controlsButtonTitle": "Contrôles", "dashboard.editingToolbar.editControlGroupButtonTitle": "Paramètres", "dashboard.editingToolbar.onlyOneTimeSliderControlMsg": "Le groupe de contrôle contient déjà un contrôle de curseur temporel.", + "dashboard.editorMenu.addPanelFlyout.searchLabelText": "champ de recherche pour les panneaux", "dashboard.editorMenu.deprecatedTag": "Déclassé", "dashboard.embeddableApi.showSettings.flyout.applyButtonTitle": "Appliquer", "dashboard.embeddableApi.showSettings.flyout.cancelButtonTitle": "Annuler", @@ -1244,6 +1659,7 @@ "dashboard.embeddableApi.showSettings.flyout.form.panelTitleInputAriaLabel": "Modifier le titre du tableau de bord", "dashboard.embeddableApi.showSettings.flyout.form.storeTimeWithDashboardFormRowHelpText": "Le filtre temporel est défini sur l’option sélectionnée chaque fois que ce tableau de bord est chargé.", "dashboard.embeddableApi.showSettings.flyout.form.storeTimeWithDashboardFormRowLabel": "Enregistrer la plage temporelle avec le tableau de bord", + "dashboard.embeddableApi.showSettings.flyout.form.syncColorsBetweenPanelsSwitchHelp": "Valide uniquement pour les palettes {default} et {compatibility}", "dashboard.embeddableApi.showSettings.flyout.form.syncColorsBetweenPanelsSwitchLabel": "Synchroniser les palettes de couleur de tous les panneaux", "dashboard.embeddableApi.showSettings.flyout.form.syncCursorBetweenPanelsSwitchLabel": "Synchroniser le curseur de tous les panneaux", "dashboard.embeddableApi.showSettings.flyout.form.syncTooltipsBetweenPanelsSwitchLabel": "Synchroniser les infobulles de tous les panneaux", @@ -1294,8 +1710,14 @@ "dashboard.listing.unsaved.unsavedChangesTitle": "Vous avez des modifications non enregistrées dans le {dash} suivant :", "dashboard.loadingError.dashboardGridErrorMessage": "Impossible de charger le tableau de bord : {message}", "dashboard.loadURLError.PanelTooOld": "Impossible de charger les panneaux à partir d'une URL créée dans une version antérieure à 7.3", + "dashboard.managedContentBadge.ariaLabel": "Elastic gère ce tableau de bord. Dupliquez-le pour apporter des modifications.", + "dashboard.managedContentPopoverButton": "Elastic gère ce tableau de bord. {Duplicate}-le pour y apporter des modifications.", + "dashboard.managedContentPopoverButtonText": "Dupliquer", + "dashboard.managedContentPopoverFooterText": "Cliquez ici pour dupliquer ce tableau de bord", "dashboard.noMatchRoute.bannerText": "L'application de tableau de bord ne reconnaît pas ce chemin : {route}.", "dashboard.noMatchRoute.bannerTitleText": "Page introuvable", + "dashboard.palettes.defaultPaletteLabel": "Par défaut", + "dashboard.palettes.kibanaPaletteLabel": "Compatibilité", "dashboard.panel.AddToLibrary": "Enregistrer dans la bibliothèque", "dashboard.panel.addToLibrary.errorMessage": "Une erreur s'est produite lors de l'ajout du panneau {panelTitle} à la bibliothèque", "dashboard.panel.addToLibrary.successMessage": "Le panneau {panelTitle} a été ajouté à la bibliothèque", @@ -1329,7 +1751,7 @@ "dashboard.renderer.404Body": "Désolé, le tableau de bord que vous recherchez est introuvable. Elle a peut-être été retirée ou renommée, ou peut-être qu'elle n'a jamais existé.", "dashboard.renderer.404Title": "Tableau de bord introuvable", "dashboard.resetChangesConfirmModal.confirmButtonLabel": "Réinitialiser le tableau de bord", - "dashboard.resetChangesConfirmModal.resetChangesDescription": "Ce tableau de bord va revenir à son dernier état d'enregistrement. Vous risquez de perdre les modifications apportées aux filtres et aux requêtes.", + "dashboard.resetChangesConfirmModal.resetChangesDescription": "Ce tableau de bord va revenir à son dernier état d'enregistrement. Vous risquez de perdre les modifications apportées aux filtres et aux requêtes.", "dashboard.resetChangesConfirmModal.resetChangesTitle": "Réinitialiser le tableau de bord ?", "dashboard.savedDashboard.newDashboardTitle": "Nouveau tableau de bord", "dashboard.share.defaultDashboardTitle": "Tableau de bord [{date}]", @@ -1338,6 +1760,7 @@ "dashboard.solutionToolbar.addPanelButtonLabel": "Créer une visualisation", "dashboard.solutionToolbar.addPanelFlyout.cancelButtonText": "Fermer", "dashboard.solutionToolbar.addPanelFlyout.headingText": "Ajouter un panneau", + "dashboard.solutionToolbar.addPanelFlyout.loadingErrorDescription": "Une erreur est survenue lors du chargement des panneaux du tableau de bord disponibles pour la sélection", "dashboard.solutionToolbar.addPanelFlyout.noResultsDescription": "Aucun type de panneaux trouvé", "dashboard.solutionToolbar.editorMenuButtonLabel": "Ajouter un panneau", "dashboard.solutionToolbar.quickCreateButtonGroupLegend": "Raccourcis vers les types de visualisation populaires", @@ -1368,7 +1791,7 @@ "dashboard.topNave.viewModeInteractiveSaveButtonAriaLabel": "dupliquer", "dashboard.topNave.viewModeInteractiveSaveConfigDescription": "Créer une copie du tableau de bord", "dashboard.unsavedChangesBadge": "Modifications non enregistrées", - "dashboard.unsavedChangesBadgeToolTipContent": " Vous avez des modifications non enregistrées dans ce tableau de bord. Pour supprimer cette étiquette, enregistrez le tableau de bord.", + "dashboard.unsavedChangesBadgeToolTipContent": "Vous avez des modifications non enregistrées dans ce tableau de bord. Pour supprimer cette étiquette, enregistrez le tableau de bord.", "dashboard.viewmodeBackup.error": "Une erreur s'est produite lors de la sauvegarde du mode d'affichage : {message}", "data.advancedSettings.autocompleteIgnoreTimerange": "Utiliser la plage temporelle", "data.advancedSettings.autocompleteIgnoreTimerangeText": "Désactivez cette propriété pour obtenir des suggestions de saisie semi-automatique depuis l’intégralité de l’ensemble de données plutôt que depuis la plage temporelle définie. {learnMoreLink}", @@ -1386,7 +1809,7 @@ "data.advancedSettings.courier.requestPreferenceCustom": "Personnalisée", "data.advancedSettings.courier.requestPreferenceNone": "Aucune", "data.advancedSettings.courier.requestPreferenceSessionId": "ID session", - "data.advancedSettings.courier.requestPreferenceText": "Permet de définir quelles partitions doivent gérer les requêtes de recherche.\n
      \n
    • {sessionId} : limite les opérations pour exécuter toutes les requêtes de recherche sur les mêmes partitions.\n Cela a l'avantage de réutiliser les caches de partition pour toutes les requêtes.
    • \n
    • {custom} : permet de définir une valeur de préférence.\n Utilisez courier:customRequestPreference pour personnaliser votre valeur de préférence.
    • \n
    • {none} : permet de ne pas définir de préférence.\n Cela peut permettre de meilleures performances, car les requêtes peuvent être réparties entre toutes les copies de partition.\n Cependant, les résultats peuvent être incohérents, les différentes partitions pouvant se trouver dans différents états d'actualisation.
    • \n
    ", + "data.advancedSettings.courier.requestPreferenceText": "Permet de définir quelles partitions doivent gérer les requêtes de recherche.
    • {sessionId} : limite les opérations pour exécuter toutes les requêtes de recherche sur les mêmes partitions. Cela a l'avantage de réutiliser les caches de partition pour toutes les requêtes.
    • {custom} : permet de définir une valeur de préférence. Utilisez courier:customRequestPreference pour personnaliser votre valeur de préférence.
    • {none} : permet de ne pas définir de préférence. Cela peut permettre de meilleures performances, car les requêtes peuvent être réparties entre toutes les copies de partition. Cependant, les résultats peuvent être incohérents, les différentes partitions pouvant se trouver dans différents états d'actualisation.
    ", "data.advancedSettings.courier.requestPreferenceTitle": "Préférence de requête", "data.advancedSettings.defaultIndexText": "Utilisé par Discover et Visualisations lorsqu'une vue de données n'est pas définie.", "data.advancedSettings.defaultIndexTitle": "Vue de données par défaut", @@ -1394,7 +1817,7 @@ "data.advancedSettings.docTableHighlightTitle": "Mettre les résultats en surbrillance", "data.advancedSettings.histogram.barTargetText": "Tente de générer ce nombre de compartiments lorsque l’intervalle \"auto\" est utilisé dans des histogrammes numériques et de date.", "data.advancedSettings.histogram.barTargetTitle": "Nombre de compartiments cible", - "data.advancedSettings.histogram.maxBarsText": "\n Limite la densité des histogrammes numériques et de date dans tout Kibana\n pour de meilleures performances à l’aide d’une requête de test. Si la requête de test génère trop de compartiments,\n l'intervalle entre les compartiments est augmenté. Ce paramètre s'applique séparément\n pour chaque agrégation d'histogrammes et ne s'applique pas aux autres types d'agrégations.\n Pour identifier la valeur maximale de ce paramètre, divisez la valeur \"search.max_buckets\" d'Elasticsearch\n par le nombre maximal d'agrégations dans chaque visualisation.\n ", + "data.advancedSettings.histogram.maxBarsText": "Avec une requête de test, limite la densité des histogrammes de dates et de nombres sur Kibana pour garantir de meilleures performances. Si la requête de test génère trop de compartiments, l'intervalle entre les compartiments est augmenté. Ce paramètre s'applique séparément pour chaque agrégation d'histogrammes et ne s'applique pas aux autres types d'agrégations. Pour trouver la valeur maximale de ce paramètre, divisez la valeur \"search.max_buckets\" d'Elasticsearch par le nombre maximal d'agrégations dans chaque visualisation.", "data.advancedSettings.histogram.maxBarsTitle": "Nombre maximal de compartiments", "data.advancedSettings.historyLimitText": "Le nombre de valeurs les plus récentes qui s’affichent pour les champs associés à un historique (par exemple, les entrées de requête).", "data.advancedSettings.historyLimitTitle": "Limite d'historique", @@ -1529,7 +1952,7 @@ "data.search.aggs.buckets.dateHistogram.customLabel.help": "Représente une étiquette personnalisée pour cette agrégation", "data.search.aggs.buckets.dateHistogram.dropPartials.help": "Spécifie l'utilisation ou non de drop_partials pour cette agrégation.", "data.search.aggs.buckets.dateHistogram.enabled.help": "Spécifie si cette agrégation doit être activée.", - "data.search.aggs.buckets.dateHistogram.extendedBounds.help": "Avec le paramètre extended_bounds, il est désormais possible de \"forcer\" l'agrégation d'histogrammes à démarrer la conception des compartiments sur une valeur minimale spécifique et à continuer jusqu'à une valeur maximale. ", + "data.search.aggs.buckets.dateHistogram.extendedBounds.help": "Avec le paramètre extended_bounds, il est désormais possible de \"forcer\" l'agrégation d'histogrammes à démarrer la conception des compartiments sur une valeur minimale spécifique et à continuer jusqu'à une valeur maximale.", "data.search.aggs.buckets.dateHistogram.extendToTimeRange.help": "Définit automatiquement les limites étendues sur la plage temporelle appliquée actuellement. Est ignoré si extended_bounds est défini", "data.search.aggs.buckets.dateHistogram.field.help": "Champ à utiliser pour cette agrégation", "data.search.aggs.buckets.dateHistogram.format.help": "Format à utiliser pour cette agrégation", @@ -1586,7 +2009,7 @@ "data.search.aggs.buckets.histogram.autoExtendBounds.help": "Définissez cette option comme vraie pour étendre les limites au domaine des données. Cela permet de s’assurer que chaque compartiment d'intervalle compris dans ces limites créera une ligne de tableau distincte.", "data.search.aggs.buckets.histogram.customLabel.help": "Représente une étiquette personnalisée pour cette agrégation", "data.search.aggs.buckets.histogram.enabled.help": "Spécifie si cette agrégation doit être activée.", - "data.search.aggs.buckets.histogram.extendedBounds.help": "Avec le paramètre extended_bounds, il est désormais possible de \"forcer\" l'agrégation d'histogrammes à démarrer la conception des compartiments sur une valeur minimale spécifique et à continuer jusqu'à une valeur maximale. ", + "data.search.aggs.buckets.histogram.extendedBounds.help": "Avec le paramètre extended_bounds, il est désormais possible de \"forcer\" l'agrégation d'histogrammes à démarrer la conception des compartiments sur une valeur minimale spécifique et à continuer jusqu'à une valeur maximale.", "data.search.aggs.buckets.histogram.field.help": "Champ à utiliser pour cette agrégation", "data.search.aggs.buckets.histogram.hasExtendedBounds.help": "Spécifie l'utilisation ou non de has_extended_bounds pour cette agrégation.", "data.search.aggs.buckets.histogram.id.help": "ID pour cette agrégation", @@ -2219,6 +2642,8 @@ "data.searchSessionIndicator.canceledTooltipText": "La session de recherche s'est arrêtée", "data.searchSessionIndicator.canceledWhenText": "Arrêtée {when}", "data.searchSessionIndicator.continueInBackgroundButtonText": "Enregistrer la session", + "data.searchSessionIndicator.deprecationWarning.textParagraphOne": "Les sessions de recherche sont obsolètes et seront supprimées dans une future version.", + "data.searchSessionIndicator.deprecationWarning.title": "Déclassé dans la version 8.15.0", "data.searchSessionIndicator.disabledDueToDisabledGloballyMessage": "Vous ne disposez pas d'autorisations pour gérer les sessions de recherche", "data.searchSessionIndicator.disabledDueToTimeoutMessage": "Les résultats de la session de recherche ont expiré.", "data.searchSessionIndicator.loadingInTheBackgroundDescriptionText": "Vous pouvez retourner aux résultats terminés à partir de la page Gestion", @@ -2316,6 +2741,7 @@ "discover.advancedSettings.disableDocumentExplorerDescription": "Désactivez cette option pour utiliser le nouveau {documentExplorerDocs} au lieu de la vue classique. l'explorateur de documents offre un meilleur tri des données, des colonnes redimensionnables et une vue en plein écran.", "discover.advancedSettings.discover.disableDocumentExplorerDeprecation": "Ce paramètre est déclassé et sera supprimé dans la version 9.0 de Kibana.", "discover.advancedSettings.discover.fieldStatisticsLinkText": "Vue des statistiques de champ", + "discover.advancedSettings.discover.maxCellHeightDeprecation": "Ce paramètre est déclassé et sera supprimé dans la version 9.0 de Kibana.", "discover.advancedSettings.discover.modifyColumnsOnSwitchText": "Supprimez les colonnes qui ne sont pas disponibles dans la nouvelle vue de données.", "discover.advancedSettings.discover.modifyColumnsOnSwitchTitle": "Modifier les colonnes en cas de changement des vues de données", "discover.advancedSettings.discover.multiFieldsLinkText": "champs multiples", @@ -2374,6 +2800,13 @@ "discover.context.unableToLoadDocumentDescription": "Impossible de charger les documents", "discover.contextViewRoute.errorMessage": "Aucune donnée correspondante pour l'ID {dataViewId}", "discover.contextViewRoute.errorTitle": "Une erreur s'est produite", + "discover.customControl.degradedDocArialLabel": "Accéder aux documents dégradés", + "discover.customControl.degradedDocDisabled": "La détection des champs de documents dégradés est désactivée pour cette recherche. Cliquez pour ajouter une {directive} à votre requête ES|QL.", + "discover.customControl.degradedDocNotPresent": "Tous les champs de ce document ont été analysés correctement", + "discover.customControl.degradedDocPresent": "Ce document n'a pas pu être analysé correctement. Tous les champs n'ont pas été remplis correctement.", + "discover.customControl.stacktrace.available": "Traces d'appel disponibles", + "discover.customControl.stacktrace.notAvailable": "Traces d'appel indisponibles", + "discover.customControl.stacktraceArialLabel": "Accès aux traces d'appel disponibles", "discover.discoverBreadcrumbTitle": "Discover", "discover.discoverDefaultSearchSessionName": "Discover", "discover.discoverDescription": "Explorez vos données de manière interactive en interrogeant et en filtrant des documents bruts.", @@ -2420,18 +2853,22 @@ "discover.docTable.tableRow.viewSingleDocumentLinkText": "Afficher un seul document", "discover.docTable.tableRow.viewSurroundingDocumentsLinkText": "Afficher les documents alentour", "discover.documentsAriaLabel": "Documents", + "discover.docViews.logsOverview.title": "Aperçu du log", "discover.docViews.table.scoreSortWarningTooltip": "Filtrez sur _score pour pouvoir récupérer les valeurs correspondantes.", "discover.dropZoneTableLabel": "Abandonner la zone pour ajouter un champ en tant que colonne dans la table", "discover.embeddable.inspectorRequestDataTitle": "Données", "discover.embeddable.inspectorRequestDescription": "Cette requête interroge Elasticsearch afin de récupérer les données pour la recherche.", + "discover.embeddable.search.dataViewError": "Vue de données {indexPatternId} manquante", "discover.embeddable.search.displayName": "rechercher", + "discover.errorCalloutESQLReferenceButtonLabel": "Ouvrir la référence ES|QL", "discover.errorCalloutShowErrorMessage": "Afficher les détails", "discover.esqlMode.selectedColumnsCallout": "Affichage de {selectedColumnsNumber} champs sur {esqlQueryColumnsNumber}. Ajoutez-en d’autres depuis la liste des champs disponibles.", - "discover.esqlToDataViewTransitionModal.closeButtonLabel": "Basculer sans sauvegarder", - "discover.esqlToDataViewTransitionModal.dismissButtonLabel": "Ne plus afficher cet avertissement", + "discover.esqlToDataViewTransitionModal.closeButtonLabel": "Annuler et changer", + "discover.esqlToDataViewTransitionModal.dismissButtonLabel": "Ne plus me demander", + "discover.esqlToDataViewTransitionModal.feedbackLink": "Soumettre des commentaires ES|QL", "discover.esqlToDataViewTransitionModal.saveButtonLabel": "Sauvegarder et basculer", - "discover.esqlToDataViewTransitionModal.title": "Votre requête sera supprimée", - "discover.esqlToDataviewTransitionModalBody": "Modifier la vue de données supprime la requête ES|QL en cours. Sauvegardez cette recherche pour ne pas perdre de travail.", + "discover.esqlToDataViewTransitionModal.title": "Modifications non enregistrées", + "discover.esqlToDataviewTransitionModalBody": "Un changement de vue de données supprime la requête ES|QL en cours. Sauvegardez cette recherche pour éviter de perdre votre travail.", "discover.fieldChooser.availableFieldsTooltip": "Champs disponibles pour l'affichage dans le tableau.", "discover.fieldChooser.discoverField.addFieldTooltip": "Ajouter le champ en tant que colonne", "discover.fieldChooser.discoverField.removeFieldTooltip": "Supprimer le champ du tableau", @@ -2461,6 +2898,7 @@ "discover.loadingDocuments": "Chargement des documents", "discover.loadingResults": "Chargement des résultats", "discover.localMenu.alertsDescription": "Alertes", + "discover.localMenu.esqlTooltipLabel": "ES|QL est le nouveau langage de requête canalisé puissant d'Elastic.", "discover.localMenu.fallbackReportTitle": "Recherche Discover sans titre", "discover.localMenu.inspectTitle": "Inspecter", "discover.localMenu.localMenu.alertsTitle": "Alertes", @@ -2475,7 +2913,21 @@ "discover.localMenu.saveTitle": "Enregistrer", "discover.localMenu.shareSearchDescription": "Partager la recherche", "discover.localMenu.shareTitle": "Partager", + "discover.localMenu.switchToClassicTitle": "Basculer vers le classique", + "discover.localMenu.switchToClassicTooltipLabel": "Passez à la syntaxe KQL ou Lucene.", + "discover.localMenu.tryESQLTitle": "Essayer ES|QL", + "discover.logLevelLabels.alert": "Alerte", + "discover.logLevelLabels.critical": "Critique", + "discover.logLevelLabels.debug": "Déboguer", + "discover.logLevelLabels.emergency": "Urgence", + "discover.logLevelLabels.error": "Erreur", + "discover.logLevelLabels.fatal": "Fatal", + "discover.logLevelLabels.info": "Infos", + "discover.logLevelLabels.notice": "Notification", + "discover.logLevelLabels.trace": "Trace", + "discover.logLevelLabels.warning": "Avertissement", "discover.logs.dataTable.header.popover.content": "Contenu", + "discover.logs.dataTable.header.popover.json": "JSON", "discover.logs.dataTable.header.popover.resource": "Ressource", "discover.logs.flyoutDetail.value.hover.filterFor": "Filtrer sur cette {value}", "discover.logs.flyoutDetail.value.hover.filterOut": "Exclure cette {value}", @@ -2560,7 +3012,7 @@ "discover.viewAlert.alertRuleFetchErrorTitle": "Erreur lors de la récupération de la règle d'alerte", "discover.viewAlert.dataViewErrorText": "Échec de la vue des données de la règle d'alerte avec l'ID {alertId}.", "discover.viewAlert.dataViewErrorTitle": "Erreur lors de la récupération de la vue de données", - "discover.viewAlert.documentsMayVaryInfoDescription": "Les documents affichés peuvent différer de ceux ayant déclenché l'alerte.\n Des documents ont peut-être été ajoutés ou supprimés.", + "discover.viewAlert.documentsMayVaryInfoDescription": "Les documents affichés peuvent différer de ceux ayant déclenché l'alerte. Des documents ont peut-être été ajoutés ou supprimés.", "discover.viewAlert.documentsMayVaryInfoTitle": "Les documents affichés peuvent varier", "discover.viewAlert.searchSourceErrorTitle": "Erreur lors de la récupération de la source de recherche", "discover.viewModes.document.label": "Documents", @@ -2568,7 +3020,7 @@ "discover.viewModes.patternAnalysis.label": "Modèles {patternCount}", "domDragDrop.announce.cancelled": "Mouvement annulé. {label} revenu à sa position initiale", "domDragDrop.announce.cancelledItem": "Mouvement annulé. {label} revenu au groupe {groupLabel} à la position {position}", - "domDragDrop.announce.combine.short": " Maintenir la touche Contrôle enfoncée pour combiner", + "domDragDrop.announce.combine.short": "Maintenir la touche Contrôle enfoncée pour combiner", "domDragDrop.announce.dropped.combineCompatible": "Combinaisons de {label} dans le {groupLabel} vers {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition} dans le calque {dropLayerNumber}", "domDragDrop.announce.dropped.combineIncompatible": "Conversion de {label} en {nextLabel} dans le groupe {groupLabel} à la position {position} et combinaison avec {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition} dans le calque {dropLayerNumber}", "domDragDrop.announce.dropped.duplicated": "{label} dupliqué dans le groupe {groupLabel} à la position {position} dans le calque {layerNumber}", @@ -2582,7 +3034,7 @@ "domDragDrop.announce.dropped.swapIncompatible": "Conversion de {label} en {nextLabel} dans le groupe {groupLabel} à la position {position} dans le calque {layerNumber} et permuté avec {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition} dans le calque {dropLayerNumber}", "domDragDrop.announce.droppedDefault": "Ajout de {label} dans le groupe {dropGroupLabel} à la position {position} dans le calque {dropLayerNumber}", "domDragDrop.announce.droppedNoPosition": "{label} ajouté à {dropLabel}", - "domDragDrop.announce.duplicate.short": " Maintenez la touche Alt ou Option enfoncée pour dupliquer.", + "domDragDrop.announce.duplicate.short": "Maintenez la touche Alt ou Option enfoncée pour dupliquer.", "domDragDrop.announce.duplicated.combine": "Combinaison de {dropLabel} avec {label} dans {groupLabel} à la position {position} dans le calque {dropLayerNumber}", "domDragDrop.announce.duplicated.replace": "Remplacement de {dropLabel} par {label} dans {groupLabel} à la position {position} dans le calque {dropLayerNumber}", "domDragDrop.announce.duplicated.replaceDuplicateCompatible": "Remplacement de {dropLabel} par une copie de {label} dans {groupLabel} à la position {position} dans le calque {dropLayerNumber}", @@ -2611,7 +3063,7 @@ "domDragDrop.announce.selectedTarget.replaceMain": "Vous faites glisser {label} à partir de {groupLabel} à la position {position} dans le calque {layerNumber} sur {dropLabel} à partir du groupe {dropGroupLabel} à la position {dropPosition} dans le calque {dropLayerNumber}. Appuyez sur la barre d'espace ou sur Entrée pour remplacer {dropLabel} par {label}.{duplicateCopy}{swapCopy}{combineCopy}", "domDragDrop.announce.selectedTarget.swapCompatible": "Permutation de {label} dans le groupe {groupLabel} à la position {position} dans le calque {layerNumber} et de {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition} dans le calque {dropLayerNumber}. Maintenir la touche Maj enfoncée tout en appuyant sur la barre d'espace ou sur Entrée pour permuter", "domDragDrop.announce.selectedTarget.swapIncompatible": "Conversion de {label} en {nextLabel} dans le groupe {groupLabel} à la position {position} dans le calque {layerNumber} et permutation avec {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition} dans le calque {dropLayerNumber}. Maintenir la touche Maj enfoncée tout en appuyant sur la barre d'espace ou sur Entrée pour permuter", - "domDragDrop.announce.swap.short": " Maintenez la touche Maj enfoncée pour permuter.", + "domDragDrop.announce.swap.short": "Maintenez la touche Maj enfoncée pour permuter.", "domDragDrop.dropTargets.altOption": "Alt/Option", "domDragDrop.dropTargets.combine": "Combiner", "domDragDrop.dropTargets.control": "Contrôler", @@ -2655,6 +3107,37 @@ "embeddableApi.selectRangeTrigger.title": "Sélection de la plage", "embeddableApi.valueClickTrigger.description": "Un point de données cliquable sur la visualisation", "embeddableApi.valueClickTrigger.title": "Clic unique", + "embeddableExamples.dataTable.ariaLabel": "Tableau de données", + "embeddableExamples.dataTable.noDataViewError": "Au moins une vue de données est requise pour utiliser l'exemple de table de données.", + "embeddableExamples.euiMarkdownEditor.displayNameAriaLabel": "Markdown EUI", + "embeddableExamples.euiMarkdownEditor.embeddableAriaLabel": "Éditeur de markdown du tableau de bord", + "embeddableExamples.savedbook.addBookAction.displayName": "Livre", + "embeddableExamples.savedbook.editBook.displayName": "livre", + "embeddableExamples.savedBook.editor.addToLibrary": "Enregistrer dans la bibliothèque", + "embeddableExamples.savedBook.editor.authorLabel": "Auteur", + "embeddableExamples.savedBook.editor.cancel": "Abandonner les modifications", + "embeddableExamples.savedBook.editor.create": "Créer un livre", + "embeddableExamples.savedBook.editor.editTitle": "Modifier un livre", + "embeddableExamples.savedBook.editor.newTitle": "Créer un nouveau livre", + "embeddableExamples.savedBook.editor.pagesLabel": "Nombre de pages", + "embeddableExamples.savedBook.editor.save": "Conserver les modifications", + "embeddableExamples.savedBook.editor.synopsisLabel": "Synopsis", + "embeddableExamples.savedBook.editor.titleLabel": "Titre", + "embeddableExamples.savedBook.libraryCallout": "Enregistré dans la bibliothèque", + "embeddableExamples.savedBook.noLibraryCallout": "Non enregistré dans la bibliothèque", + "embeddableExamples.savedBook.numberOfPages": "{numberOfPages} pages", + "embeddableExamples.search.dataViewName": "{dataViewName}", + "embeddableExamples.search.noDataViewError": "Veuillez installer une vue de données pour visualiser cet exemple", + "embeddableExamples.search.result": "{count, plural, one {document trouvé} other {documents trouvés}}", + "embeddableExamples.unifiedFieldList.displayName": "Liste des champs", + "embeddableExamples.unifiedFieldList.noDefaultDataViewErrorMessage": "La liste de champs doit être utilisée avec au moins une vue de données présente", + "embeddableExamples.unifiedFieldList.selectDataViewMessage": "Veuillez sélectionner une vue de données", + "esql.advancedSettings.enableESQLDescription": "Ce paramètre active ES|QL dans Kibana. En le désactivant, vous cacherez l'interface utilisateur ES|QL de diverses applications. Cependant, les utilisateurs pourront accéder aux recherches enregistrées ES|QL, en plus des visualisations, etc.", + "esql.advancedSettings.enableESQLTitle": "Activer ES|QL", + "esql.triggers.updateEsqlQueryTrigger": "Mettre à jour la requête ES|QL", + "esql.triggers.updateEsqlQueryTriggerDescription": "Mettre à jour la requête ES|QL en utilisant une nouvelle requête", + "esql.updateESQLQueryLabel": "Mettre à jour la requête ES|QL dans l’éditeur", + "esqlDataGrid.openInDiscoverLabel": "Ouvrir dans Discover", "esqlEditor.query.aborted": "La demande a été annulée", "esqlEditor.query.cancel": "Annuler", "esqlEditor.query.collapseLabel": "Réduire", @@ -2665,6 +3148,8 @@ "esqlEditor.query.expandLabel": "Développer", "esqlEditor.query.feedback": "Commentaires", "esqlEditor.query.hideQueriesLabel": "Masquer les recherches récentes", + "esqlEditor.query.limitInfo": "LIMITE : {limit} lignes", + "esqlEditor.query.limitInfoReduced": "LIMITE : {limit}", "esqlEditor.query.lineCount": "{count} {count, plural, one {ligne} other {lignes}}", "esqlEditor.query.lineNumber": "Ligne {lineNumber}", "esqlEditor.query.querieshistory.error": "La requête a échouée", @@ -2673,10 +3158,12 @@ "esqlEditor.query.querieshistoryRun": "Exécuter la requête", "esqlEditor.query.querieshistoryTable": "Tableau d'historique des recherches", "esqlEditor.query.recentQueriesColumnLabel": "Recherches récentes", + "esqlEditor.query.refreshLabel": "Actualiser", "esqlEditor.query.runQuery": "Exécuter la requête", "esqlEditor.query.showQueriesLabel": "Afficher les recherches récentes", "esqlEditor.query.submitFeedback": "Soumettre un commentaire", "esqlEditor.query.timeRanColumnLabel": "Temps exécuté", + "esqlEditor.query.timestampDetected": "{detectedTimestamp} trouvé", "esqlEditor.query.timestampNotDetected": "@timestamp non trouvé", "esqlEditor.query.warningCount": "{count} {count, plural, one {avertissement} other {avertissements}}", "esqlEditor.query.warningsTitle": "Avertissements", @@ -2796,6 +3283,7 @@ "eventAnnotation.rangeAnnotation.args.time": "Horodatage de l'annotation", "eventAnnotation.rangeAnnotation.description": "Configurer l'annotation manuelle", "eventAnnotationCommon.manualAnnotation.defaultAnnotationLabel": "Événement", + "eventAnnotationCommon.manualAnnotation.defaultRangeAnnotationLabel": "Plage d'événements", "eventAnnotationComponents.eventAnnotationGroup.metadata.name": "Groupes d’annotations", "eventAnnotationComponents.eventAnnotationGroup.savedObjectFinder.emptyCTA": "Créer un calque d’annotations", "eventAnnotationComponents.eventAnnotationGroup.savedObjectFinder.emptyPromptDescription": "Il n’y a actuellement aucune annotation disponible à sélectionner depuis la bibliothèque. Créez un nouveau calque pour ajouter des annotations.", @@ -2915,12 +3403,23 @@ "exceptionList-components.exceptions.exceptionItem.card.metaDetailsBy": "par", "exceptionList-components.exceptions.exceptionItem.card.showCommentsLabel": "Afficher {comments, plural, =1 {commentaire} other {commentaires}} ({comments})", "exceptionList-components.exceptions.exceptionItem.card.updatedLabel": "Mis à jour", + "exceptionList-components.partialCodeSignatureCallout.body": "Veuillez vérifier les valeurs des champs, car vos critères de filtrage peuvent être incomplets. Nous recommandons d'inclure à la fois le nom du signataire et le statut de confiance (en utilisant l'opérateur « AND ») pour éviter d'éventuelles failles de sécurité.", + "exceptionList-components.partialCodeSignatureCallout.title": "Veuillez examiner vos entrées", "exceptionList-components.wildcardWithWrongOperatorCallout.body": "L'utilisation de \"*\" ou de \"?\" dans la valeur avec l'opérateur \"is\" peut rendre l'entrée inefficace. Remplacez {operator} par \"{matches}\" pour que les caractères génériques s'exécutent correctement.", "exceptionList-components.wildcardWithWrongOperatorCallout.changeTheOperator": "Changer d'opérateur", "exceptionList-components.wildcardWithWrongOperatorCallout.matches": "correspond à", "exceptionList-components.wildcardWithWrongOperatorCallout.title": "Veuillez examiner vos entrées", "expandableFlyout.previewSection.backButton": "Retour", "expandableFlyout.previewSection.closeButton": "Fermer", + "expandableFlyout.renderMenu.flyoutResizeButton": "Réinitialiser la taille", + "expandableFlyout.renderMenu.flyoutResizeTitle": "Taille du menu volant", + "expandableFlyout.settingsMenu.flyoutTypeTitle": "Type de menu volant", + "expandableFlyout.settingsMenu.overlayMode": "Superposer", + "expandableFlyout.settingsMenu.overlayTooltip": "Affiche le menu volant sur la page", + "expandableFlyout.settingsMenu.popoverButton": "Paramètres du menu volant", + "expandableFlyout.settingsMenu.popoverTitle": "Paramètres du menu volant", + "expandableFlyout.settingsMenu.pushMode": "Déploiement", + "expandableFlyout.settingsMenu.pushTooltip": "Affiche le menu volant à côté de la page", "expressionError.errorComponent.description": "Échec de l'expression avec le message :", "expressionError.errorComponent.title": "Oups ! Échec de l'expression", "expressionError.renderer.debug.displayName": "Déboguer", @@ -3030,6 +3529,7 @@ "expressionMetricVis.function.dimension.timeField": "Champ temporel", "expressionMetricVis.function.help": "Visualisation de l'indicateur", "expressionMetricVis.function.icon.help": "Fournit une icône de visualisation statique.", + "expressionMetricVis.function.iconAlign.help": "L'alignement de l'icône.", "expressionMetricVis.function.inspectorTableId.help": "ID pour le tableau de l'inspecteur", "expressionMetricVis.function.max.help.": "La dimension contenant la valeur maximale.", "expressionMetricVis.function.metric.help": "L’indicateur principal.", @@ -3040,7 +3540,10 @@ "expressionMetricVis.function.secondaryMetric.help": "L’indicateur secondaire (affiché au-dessus de l’indicateur principal).", "expressionMetricVis.function.secondaryPrefix.help": "Texte facultatif à afficher avant secondaryMetric.", "expressionMetricVis.function.subtitle.help": "Le sous-titre pour un indicateur unique. Remplacé si breakdownBy est spécifié.", + "expressionMetricVis.function.titlesTextAlign.help": "L'alignement du titre et du sous-titre.", "expressionMetricVis.function.trendline.help": "Configuration de la courbe de tendance facultative", + "expressionMetricVis.function.valueFontSize.help": "La taille de la police de valeur.", + "expressionMetricVis.function.valuesTextAlign.help": "L'alignement des indicateurs primaires et secondaires.", "expressionMetricVis.trendA11yDescription": "Graphique linéaire affichant la tendance de l'indicateur principal sur la durée.", "expressionMetricVis.trendA11yTitle": "{dataTitle} sur la durée.", "expressionMetricVis.trendline.function.breakdownBy.help": "La dimension contenant les étiquettes des sous-catégories.", @@ -3837,7 +4340,7 @@ "home.tutorials.ciscoLogs.longDescription": "Il s'agit d'un module pour les logs de dispositifs réseau Cisco (ASA, FTD, IOS, Nexus). Il inclut les ensembles de fichiers suivants pour la réception des logs par le biais de Syslog ou d'un ficher. [En savoir plus]({learnMoreLink}).", "home.tutorials.ciscoLogs.nameTitle": "Logs Cisco", "home.tutorials.ciscoLogs.shortDescription": "Collectez et analysez les logs à partir des périphériques réseau Cisco avec Filebeat.", - "home.tutorials.cloudwatchLogs.longDescription": "Collectez les logs Cloudwatch en déployant Functionbeat à des fins d'exécution en tant que fonction AWS Lambda. [En savoir plus]({learnMoreLink}).", + "home.tutorials.cloudwatchLogs.longDescription": "Collectez les logs Cloudwatch en déployant Functionbeat à des fins d'exécution en tant que fonction AWS Lambda.", "home.tutorials.cloudwatchLogs.nameTitle": "Logs Cloudwatch AWS", "home.tutorials.cloudwatchLogs.shortDescription": "Collectez et analysez les logs à partir d'AWS Cloudwatch avec Functionbeat.", "home.tutorials.cockroachdbMetrics.artifacts.dashboards.linkLabel": "Tableau de bord des indicateurs CockroachDB", @@ -3855,16 +4358,16 @@ "home.tutorials.common.auditbeatCloudInstructions.config.rpmTitle": "Modifier la configuration", "home.tutorials.common.auditbeatCloudInstructions.config.windowsTextPre": "Modifiez {path} afin de définir les informations de connexion pour Elastic Cloud :", "home.tutorials.common.auditbeatCloudInstructions.config.windowsTitle": "Modifier la configuration", - "home.tutorials.common.auditbeatInstructions.config.debTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n> **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.auditbeatInstructions.config.debTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.auditbeatInstructions.config.debTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.auditbeatInstructions.config.debTitle": "Modifier la configuration", - "home.tutorials.common.auditbeatInstructions.config.osxTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n> **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.auditbeatInstructions.config.osxTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.auditbeatInstructions.config.osxTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.auditbeatInstructions.config.osxTitle": "Modifier la configuration", - "home.tutorials.common.auditbeatInstructions.config.rpmTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n> **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.auditbeatInstructions.config.rpmTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.auditbeatInstructions.config.rpmTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.auditbeatInstructions.config.rpmTitle": "Modifier la configuration", - "home.tutorials.common.auditbeatInstructions.config.windowsTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n > **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.auditbeatInstructions.config.windowsTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.auditbeatInstructions.config.windowsTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.auditbeatInstructions.config.windowsTitle": "Modifier la configuration", "home.tutorials.common.auditbeatInstructions.install.debTextPost": "Vous cherchez les packages 32 bits ? Consultez la [page de téléchargement]({linkUrl}).", @@ -3876,7 +4379,7 @@ "home.tutorials.common.auditbeatInstructions.install.rpmTextPre": "Vous utilisez Auditbeat pour la première fois ? Consultez le [guide de démarrage rapide]({linkUrl}).", "home.tutorials.common.auditbeatInstructions.install.rpmTitle": "Télécharger et installer Auditbeat", "home.tutorials.common.auditbeatInstructions.install.windowsTextPost": "Modifiez les paramètres sous {propertyName} dans le fichier {auditbeatPath} afin de pointer vers votre installation Elasticsearch.", - "home.tutorials.common.auditbeatInstructions.install.windowsTextPre": "Vous utilisez Auditbeat pour la première fois ? Consultez le [guide de démarrage rapide]({guideLinkUrl}).\n 1. Téléchargez le fichier .zip Auditbeat pour Windows via la page [Télécharger]({auditbeatLinkUrl}).\n 2. Extrayez le contenu du fichier compressé sous {folderPath}.\n 3. Renommez le répertoire `{directoryName}` en `Auditbeat`.\n 4. Ouvrez une invite PowerShell en tant qu'administrateur (faites un clic droit sur l'icône PowerShell et sélectionnez **Exécuter en tant qu'administrateur**). Si vous exécutez Windows XP, vous devrez peut-être télécharger et installer PowerShell.\n 5. Dans l'invite PowerShell, exécutez les commandes suivantes afin d'installer Auditbeat en tant que service Windows.", + "home.tutorials.common.auditbeatInstructions.install.windowsTextPre": "Vous utilisez Auditbeat pour la première fois ? Consultez le [guide de démarrage rapide]({guideLinkUrl}). 1. Téléchargez le fichier .zip Auditbeat pour Windows via la page [Télécharger]({auditbeatLinkUrl}). 2. Extrayez le contenu du fichier compressé sous {folderPath}. 3. Renommez le répertoire `{directoryName}` en `Auditbeat`. 4. Ouvrez une invite PowerShell en tant qu'administrateur (faites un clic droit sur l'icône PowerShell et sélectionnez **Exécuter en tant qu'administrateur**). Si vous exécutez Windows XP, vous devrez peut-être télécharger et installer PowerShell. 5. Dans l'invite PowerShell, exécutez les commandes suivantes afin d'installer Auditbeat en tant que service Windows.", "home.tutorials.common.auditbeatInstructions.install.windowsTitle": "Télécharger et installer Auditbeat", "home.tutorials.common.auditbeatInstructions.start.debTextPre": "La commande `setup` charge les tableaux de bord Kibana. Si les tableaux de bord sont déjà configurés, omettez cette commande.", "home.tutorials.common.auditbeatInstructions.start.debTitle": "Lancer Auditbeat", @@ -3912,16 +4415,16 @@ "home.tutorials.common.filebeatEnableInstructions.windowsTextPost": "Modifiez les paramètres dans le fichier `modules.d/{moduleName}.yml`. Vous devez activer au moins un ensemble de fichiers.", "home.tutorials.common.filebeatEnableInstructions.windowsTextPre": "Dans le dossier {path}, exécutez la commande suivante :", "home.tutorials.common.filebeatEnableInstructions.windowsTitle": "Activer et configurer le module {moduleName}", - "home.tutorials.common.filebeatInstructions.config.debTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n> **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.filebeatInstructions.config.debTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.filebeatInstructions.config.debTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.filebeatInstructions.config.debTitle": "Modifier la configuration", - "home.tutorials.common.filebeatInstructions.config.osxTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n> **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.filebeatInstructions.config.osxTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.filebeatInstructions.config.osxTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.filebeatInstructions.config.osxTitle": "Modifier la configuration", - "home.tutorials.common.filebeatInstructions.config.rpmTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n> **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.filebeatInstructions.config.rpmTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.filebeatInstructions.config.rpmTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.filebeatInstructions.config.rpmTitle": "Modifier la configuration", - "home.tutorials.common.filebeatInstructions.config.windowsTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n> **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.filebeatInstructions.config.windowsTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.filebeatInstructions.config.windowsTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.filebeatInstructions.config.windowsTitle": "Modifier la configuration", "home.tutorials.common.filebeatInstructions.install.debTextPost": "Vous cherchez les packages 32 bits ? Consultez la [page de téléchargement]({linkUrl}).", @@ -3933,7 +4436,7 @@ "home.tutorials.common.filebeatInstructions.install.rpmTextPre": "Vous utilisez Filebeat pour la première fois ? Consultez le [guide de démarrage rapide]({linkUrl}).", "home.tutorials.common.filebeatInstructions.install.rpmTitle": "Télécharger et installer Filebeat", "home.tutorials.common.filebeatInstructions.install.windowsTextPost": "Modifiez les paramètres sous {propertyName} dans le fichier {filebeatPath} afin de pointer vers votre installation Elasticsearch.", - "home.tutorials.common.filebeatInstructions.install.windowsTextPre": "Vous utilisez Filebeat pour la première fois ? Consultez le [guide de démarrage rapide]({guideLinkUrl}).\n 1. Téléchargez le fichier .zip Filebeat pour Windows via la page [Télécharger]({filebeatLinkUrl}).\n 2. Extrayez le contenu du fichier compressé sous {folderPath}.\n 3. Renommez le répertoire `{directoryName}` en `Filebeat`.\n 4. Ouvrez une invite PowerShell en tant qu'administrateur (faites un clic droit sur l'icône PowerShell et sélectionnez **Exécuter en tant qu'administrateur**). Si vous exécutez Windows XP, vous devrez peut-être télécharger et installer PowerShell.\n 5. Dans l'invite PowerShell, exécutez les commandes suivantes afin d'installer Filebeat en tant que service Windows.", + "home.tutorials.common.filebeatInstructions.install.windowsTextPre": "Vous utilisez Filebeat pour la première fois ? Consultez le [guide de démarrage rapide]({guideLinkUrl}). 1. Téléchargez le fichier .zip Filebeat pour Windows via la page [Télécharger]({filebeatLinkUrl}). 2. Extrayez le contenu du fichier compressé sous {folderPath}. 3. Renommez le répertoire `{directoryName}` en `Filebeat`. 4. Ouvrez une invite PowerShell en tant qu'administrateur (faites un clic droit sur l'icône PowerShell et sélectionnez **Exécuter en tant qu'administrateur**). Si vous exécutez Windows XP, vous devrez peut-être télécharger et installer PowerShell. 5. Dans l'invite PowerShell, exécutez les commandes suivantes afin d'installer Filebeat en tant que service Windows.", "home.tutorials.common.filebeatInstructions.install.windowsTitle": "Télécharger et installer Filebeat", "home.tutorials.common.filebeatInstructions.start.debTextPre": "La commande `setup` charge les tableaux de bord Kibana. Si les tableaux de bord sont déjà configurés, omettez cette commande.", "home.tutorials.common.filebeatInstructions.start.debTitle": "Lancer Filebeat", @@ -3962,10 +4465,10 @@ "home.tutorials.common.functionbeatEnableOnPremInstructions.defaultTitle": "Configurer le groupe de logs Cloudwatch", "home.tutorials.common.functionbeatEnableOnPremInstructionsOSXLinux.textPre": "Modifiez les paramètres dans le fichier `functionbeat.yml`.", "home.tutorials.common.functionbeatEnableOnPremInstructionsWindows.textPre": "Modifiez les paramètres dans le fichier {path}.", - "home.tutorials.common.functionbeatInstructions.config.osxTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n > **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.functionbeatInstructions.config.osxTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.functionbeatInstructions.config.osxTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.functionbeatInstructions.config.osxTitle": "Configurer le cluster Elastic", - "home.tutorials.common.functionbeatInstructions.config.windowsTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n > **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.functionbeatInstructions.config.windowsTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.functionbeatInstructions.config.windowsTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.functionbeatInstructions.config.windowsTitle": "Modifier la configuration", "home.tutorials.common.functionbeatInstructions.deploy.osxTextPre": "Ceci permet d'installer Functionbeat en tant que fonction Lambda. La commande `setup` vérifie la configuration d'Elasticsearch et charge le modèle d'indexation Kibana. L'omission de cette commande est normalement sans risque.", @@ -3976,7 +4479,7 @@ "home.tutorials.common.functionbeatInstructions.install.linuxTitle": "Télécharger et installer Functionbeat", "home.tutorials.common.functionbeatInstructions.install.osxTextPre": "Vous utilisez Functionbeat pour la première fois ? Consultez le [guide de démarrage rapide]({link}).", "home.tutorials.common.functionbeatInstructions.install.osxTitle": "Télécharger et installer Functionbeat", - "home.tutorials.common.functionbeatInstructions.install.windowsTextPre": "Vous utilisez Functionbeat pour la première fois ? Consultez le [guide de démarrage rapide]({functionbeatLink}).\n 1. Téléchargez le fichier .zip Functionbeat pour Windows via la page [Télécharger]({elasticLink}).\n 2. Extrayez le contenu du fichier compressé sous {folderPath}.\n 3. Renommez le répertoire `{directoryName}` en `Functionbeat`.\n 4. Ouvrez une invite PowerShell en tant qu'administrateur (faites un clic droit sur l'icône PowerShell et sélectionnez **Exécuter en tant qu'administrateur**). Si vous exécutez Windows XP, vous devrez peut-être télécharger et installer PowerShell.\n 5. Depuis l'invite PowerShell, accédez au répertoire Functionbeat :", + "home.tutorials.common.functionbeatInstructions.install.windowsTextPre": "Vous utilisez Functionbeat pour la première fois ? Consultez le [guide de démarrage rapide]({functionbeatLink}). 1. Téléchargez le fichier .zip Functionbeat pour Windows via la page [Télécharger]({elasticLink}). 2. Extrayez le contenu du fichier compressé sous {folderPath}. 3. Renommez le répertoire `{directoryName}` en `Functionbeat`. 4. Ouvrez une invite PowerShell en tant qu'administrateur (faites un clic droit sur l'icône PowerShell et sélectionnez **Exécuter en tant qu'administrateur**). Si vous exécutez Windows XP, vous devrez peut-être télécharger et installer PowerShell. 5. Depuis l'invite PowerShell, accédez au répertoire Functionbeat :", "home.tutorials.common.functionbeatInstructions.install.windowsTitle": "Télécharger et installer Functionbeat", "home.tutorials.common.functionbeatStatusCheck.buttonLabel": "Vérifier les données", "home.tutorials.common.functionbeatStatusCheck.errorText": "Aucune donnée n'a encore été reçue de Functionbeat.", @@ -4006,16 +4509,16 @@ "home.tutorials.common.heartbeatEnableOnPremInstructions.osxTextPre": "Modifiez le paramètre `heartbeat.monitors` dans le fichier `heartbeat.yml`.", "home.tutorials.common.heartbeatEnableOnPremInstructions.rpmTextPre": "Modifiez le paramètre `heartbeat.monitors` dans le fichier `heartbeat.yml`.", "home.tutorials.common.heartbeatEnableOnPremInstructions.windowsTextPre": "Modifiez le paramètre `heartbeat.monitors` dans le fichier `heartbeat.yml`.", - "home.tutorials.common.heartbeatInstructions.config.debTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n> **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.heartbeatInstructions.config.debTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.heartbeatInstructions.config.debTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.heartbeatInstructions.config.debTitle": "Modifier la configuration", - "home.tutorials.common.heartbeatInstructions.config.osxTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n> **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.heartbeatInstructions.config.osxTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.heartbeatInstructions.config.osxTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.heartbeatInstructions.config.osxTitle": "Modifier la configuration", - "home.tutorials.common.heartbeatInstructions.config.rpmTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n> **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.heartbeatInstructions.config.rpmTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.heartbeatInstructions.config.rpmTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.heartbeatInstructions.config.rpmTitle": "Modifier la configuration", - "home.tutorials.common.heartbeatInstructions.config.windowsTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n > **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.heartbeatInstructions.config.windowsTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.heartbeatInstructions.config.windowsTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.heartbeatInstructions.config.windowsTitle": "Modifier la configuration", "home.tutorials.common.heartbeatInstructions.install.debTextPost": "Vous cherchez les packages 32 bits ? Consultez la [page de téléchargement]({link}).", @@ -4026,7 +4529,7 @@ "home.tutorials.common.heartbeatInstructions.install.rpmTextPost": "Vous cherchez les packages 32 bits ? Consultez la [page de téléchargement]({link}).", "home.tutorials.common.heartbeatInstructions.install.rpmTextPre": "Vous utilisez Heartbeat pour la première fois ? Consultez le [guide de démarrage rapide]({link}).", "home.tutorials.common.heartbeatInstructions.install.rpmTitle": "Télécharger et installer Heartbeat", - "home.tutorials.common.heartbeatInstructions.install.windowsTextPre": "Vous utilisez Heartbeat pour la première fois ? Consultez le [guide de démarrage rapide]({heartbeatLink}).\n 1. Téléchargez le fichier .zip Heartbeat pour Windows via la page [Télécharger]({elasticLink}).\n 2. Extrayez le contenu du fichier compressé sous {folderPath}.\n 3. Renommez le répertoire `{directoryName}` en `Heartbeat`.\n 4. Ouvrez une invite PowerShell en tant qu'administrateur (faites un clic droit sur l'icône PowerShell et sélectionnez **Exécuter en tant qu'administrateur**). Si vous exécutez Windows XP, vous devrez peut-être télécharger et installer PowerShell.\n 5. Dans l'invite PowerShell, exécutez les commandes suivantes afin d'installer Heartbeat en tant que service Windows.", + "home.tutorials.common.heartbeatInstructions.install.windowsTextPre": "Vous utilisez Heartbeat pour la première fois ? Consultez le [guide de démarrage rapide]({heartbeatLink}). 1. Téléchargez le fichier .zip Heartbeat pour Windows via la page [Télécharger]({elasticLink}). 2. Extrayez le contenu du fichier compressé sous {folderPath}. 3. Renommez le répertoire `{directoryName}` en `Heartbeat`. 4. Ouvrez une invite PowerShell en tant qu'administrateur (faites un clic droit sur l'icône PowerShell et sélectionnez **Exécuter en tant qu'administrateur**). Si vous exécutez Windows XP, vous devrez peut-être télécharger et installer PowerShell. 5. Dans l'invite PowerShell, exécutez les commandes suivantes afin d'installer Heartbeat en tant que service Windows.", "home.tutorials.common.heartbeatInstructions.install.windowsTitle": "Télécharger et installer Heartbeat", "home.tutorials.common.heartbeatInstructions.start.debTextPre": "La commande `setup` charge le modèle d'indexation Kibana.", "home.tutorials.common.heartbeatInstructions.start.debTitle": "Lancer Heartbeat", @@ -4045,9 +4548,9 @@ "home.tutorials.common.logstashInstructions.install.java.osxTitle": "Télécharger et installer l'environnement d'exécution Java", "home.tutorials.common.logstashInstructions.install.java.windowsTextPre": "Suivez les instructions d'installation [ici]({link}).", "home.tutorials.common.logstashInstructions.install.java.windowsTitle": "Télécharger et installer l'environnement d'exécution Java", - "home.tutorials.common.logstashInstructions.install.logstash.osxTextPre": "Vous utilisez Logstash pour la première fois ? Consultez le [guide de démarrage rapide]({link}).", + "home.tutorials.common.logstashInstructions.install.logstash.osxTextPre": "Vous utilisez Logstash pour la première fois ? Consultez le [guide de démarrage rapide]({link}).", "home.tutorials.common.logstashInstructions.install.logstash.osxTitle": "Télécharger et installer Logstash", - "home.tutorials.common.logstashInstructions.install.logstash.windowsTextPre": "Vous utilisez Logstash pour la première fois ? Consultez le [guide de démarrage rapide]({logstashLink}).\n 1. [Téléchargez]({elasticLink}) le fichier .zip Logstash pour Windows.\n 2. Extrayez le contenu du fichier compressé.", + "home.tutorials.common.logstashInstructions.install.logstash.windowsTextPre": "Vous utilisez Logstash pour la première fois ? Consultez le [guide de démarrage rapide]({logstashLink}). 1. [Téléchargez]({elasticLink}) le fichier .zip Logstash pour Windows. 2. Extrayez le contenu du fichier compressé.", "home.tutorials.common.logstashInstructions.install.logstash.windowsTitle": "Télécharger et installer Logstash", "home.tutorials.common.metricbeat.cloudInstructions.gettingStarted.title": "Commencer", "home.tutorials.common.metricbeat.premCloudInstructions.gettingStarted.title": "Commencer", @@ -4070,16 +4573,16 @@ "home.tutorials.common.metricbeatEnableInstructions.windowsTextPost": "Modifiez les paramètres dans le fichier `modules.d/{moduleName}.yml`.", "home.tutorials.common.metricbeatEnableInstructions.windowsTextPre": "Dans le dossier {path}, exécutez la commande suivante :", "home.tutorials.common.metricbeatEnableInstructions.windowsTitle": "Activer et configurer le module {moduleName}", - "home.tutorials.common.metricbeatInstructions.config.debTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n > **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.metricbeatInstructions.config.debTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.metricbeatInstructions.config.debTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.metricbeatInstructions.config.debTitle": "Modifier la configuration", - "home.tutorials.common.metricbeatInstructions.config.osxTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n > **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.metricbeatInstructions.config.osxTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.metricbeatInstructions.config.osxTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.metricbeatInstructions.config.osxTitle": "Modifier la configuration", - "home.tutorials.common.metricbeatInstructions.config.rpmTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n > **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.metricbeatInstructions.config.rpmTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.metricbeatInstructions.config.rpmTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.metricbeatInstructions.config.rpmTitle": "Modifier la configuration", - "home.tutorials.common.metricbeatInstructions.config.windowsTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n > **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.metricbeatInstructions.config.windowsTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.metricbeatInstructions.config.windowsTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.metricbeatInstructions.config.windowsTitle": "Modifier la configuration", "home.tutorials.common.metricbeatInstructions.install.debTextPost": "Vous cherchez les packages 32 bits ? Consultez la [page de téléchargement]({link}).", @@ -4091,7 +4594,7 @@ "home.tutorials.common.metricbeatInstructions.install.rpmTextPre": "Vous utilisez Metricbeat pour la première fois ? Consultez le [guide de démarrage rapide]({link}).", "home.tutorials.common.metricbeatInstructions.install.rpmTitle": "Télécharger et installer Metricbeat", "home.tutorials.common.metricbeatInstructions.install.windowsTextPost": "Modifiez les paramètres sous `output.elasticsearch` dans le fichier {path} afin de pointer vers votre installation Elasticsearch.", - "home.tutorials.common.metricbeatInstructions.install.windowsTextPre": "Vous utilisez Metricbeat pour la première fois ? Consultez le [guide de démarrage rapide]({metricbeatLink}).\n 1. Téléchargez le fichier .zip Metricbeat pour Windows via la page [Télécharger]({elasticLink}).\n 2. Extrayez le contenu du fichier compressé sous {folderPath}.\n 3. Renommez le répertoire `{directoryName}` en `Metricbeat`.\n 4. Ouvrez une invite PowerShell en tant qu'administrateur (faites un clic droit sur l'icône PowerShell et sélectionnez **Exécuter en tant qu'administrateur**). Si vous exécutez Windows XP, vous devrez peut-être télécharger et installer PowerShell.\n 5. Dans l'invite PowerShell, exécutez les commandes suivantes afin d'installer Metricbeat en tant que service Windows.", + "home.tutorials.common.metricbeatInstructions.install.windowsTextPre": "Vous utilisez Metricbeat pour la première fois ? Consultez le [guide de démarrage rapide]({metricbeatLink}). 1. Téléchargez le fichier .zip Metricbeat pour Windows via la page [Télécharger]({elasticLink}). 2. Extrayez le contenu du fichier compressé sous {folderPath}. 3. Renommez le répertoire `{directoryName}` en `Metricbeat`. 4. Ouvrez une invite PowerShell en tant qu'administrateur (faites un clic droit sur l'icône PowerShell et sélectionnez **Exécuter en tant qu'administrateur**). Si vous exécutez Windows XP, vous devrez peut-être télécharger et installer PowerShell. 5. Dans l'invite PowerShell, exécutez les commandes suivantes afin d'installer Metricbeat en tant que service Windows.", "home.tutorials.common.metricbeatInstructions.install.windowsTitle": "Télécharger et installer Metricbeat", "home.tutorials.common.metricbeatInstructions.start.debTextPre": "La commande `setup` charge les tableaux de bord Kibana. Si les tableaux de bord sont déjà configurés, omettez cette commande.", "home.tutorials.common.metricbeatInstructions.start.debTitle": "Lancer Metricbeat", @@ -4106,20 +4609,20 @@ "home.tutorials.common.metricbeatStatusCheck.successText": "Des données ont été reçues de ce module.", "home.tutorials.common.metricbeatStatusCheck.text": "Vérifier que des données sont reçues du module Metricbeat `{moduleName}`", "home.tutorials.common.metricbeatStatusCheck.title": "Statut du module", - "home.tutorials.common.premCloudInstructions.option1.textPre": "Rendez-vous sur [Elastic Cloud]({link}). Enregistrez-vous si vous n'avez pas encore de compte. Un essai gratuit de 14 jours est disponible.\n\nConnectez-vous à la console Elastic Cloud.\n\nPour créer un cluster, dans la console Elastic Cloud :\n 1. Sélectionnez **Créer un déploiement** et spécifiez le **Nom du déploiement**.\n 2. Modifiez les autres options de déploiement selon les besoins (sinon, les valeurs par défaut sont très bien pour commencer).\n 3. Cliquer sur **Créer un déploiement**\n 4. Attendre la fin de la création du déploiement\n 5. Accéder à la nouvelle instance cloud Kibana et suivre les instructions de la page d'accueil de Kibana", + "home.tutorials.common.premCloudInstructions.option1.textPre": "Rendez-vous sur [Elastic Cloud]({link}). Enregistrez-vous si vous n'avez pas encore de compte. Un essai gratuit de 14 jours est disponible. Connectez-vous à la console Elastic Cloud Pour créer un cluster, il suffit de : 1. Sélectionner **Créer un déploiement** et spécifier le **Nom du déploiement** 2. Modifier les autres options de déploiement selon les besoins (sinon, les valeurs par défaut sont très bien pour commencer) 3. Cliquer sur **Créer un déploiement** 4. Attendre la fin de la création du déploiement 5. Accéder à la nouvelle instance cloud Kibana et suivre les instructions de la page d'accueil de Kibana", "home.tutorials.common.premCloudInstructions.option1.title": "Option 1 : essayer dans Elastic Cloud", - "home.tutorials.common.premCloudInstructions.option2.textPre": "Si vous exécutez cette instance Kibana sur une instance Elasticsearch hébergée, passez à la configuration manuelle.\n\nEnregistrez le point de terminaison **Elasticsearch** en tant que {urlTemplate} et le cluster **Mot de passe** en tant que {passwordTemplate} pour les conserver.", + "home.tutorials.common.premCloudInstructions.option2.textPre": "Si vous exécutez cette instance Kibana sur une instance Elasticsearch hébergée, passez à la configuration manuelle. Enregistrez le point de terminaison **Elasticsearch** en tant que {urlTemplate} et le cluster **Mot de passe** en tant que {passwordTemplate} pour les conserver.", "home.tutorials.common.premCloudInstructions.option2.title": "Option 2 : connecter un Kibana local à une instance cloud", "home.tutorials.common.winlogbeat.cloudInstructions.gettingStarted.title": "Premiers pas", "home.tutorials.common.winlogbeat.premCloudInstructions.gettingStarted.title": "Commencer", "home.tutorials.common.winlogbeat.premInstructions.gettingStarted.title": "Commencer", "home.tutorials.common.winlogbeatCloudInstructions.config.windowsTextPre": "Modifiez {path} afin de définir les informations de connexion pour Elastic Cloud :", "home.tutorials.common.winlogbeatCloudInstructions.config.windowsTitle": "Modifier la configuration", - "home.tutorials.common.winlogbeatInstructions.config.windowsTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur `elastic`, {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer le SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte digitale dans {esCertFingerprintTemplate}.\n\n > **_Important :_** n'employez pas l'utilisateur `elastic` intégré pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", + "home.tutorials.common.winlogbeatInstructions.config.windowsTextPostMarkdown": "Où {passwordTemplate} est le mot de passe de l'utilisateur \"elastic\", {esUrlTemplate} est l'URL d'Elasticsearch et {kibanaUrlTemplate} est l'URL de Kibana. Pour [configurer SSL]({configureSslUrl}) avec le certificat par défaut généré par Elasticsearch, ajoutez son empreinte dans {esCertFingerprintTemplate}. > **_Important :_** N'utilisez pas l'utilisateur intégré `elastic` pour sécuriser les clients dans un environnement de production. À la place, configurez des utilisateurs autorisés ou des clés d'API, et n'exposez pas les mots de passe dans les fichiers de configuration. [Learn more]({linkUrl}).", "home.tutorials.common.winlogbeatInstructions.config.windowsTextPre": "Modifiez {path} afin de définir les informations de connexion :", "home.tutorials.common.winlogbeatInstructions.config.windowsTitle": "Modifier la configuration", "home.tutorials.common.winlogbeatInstructions.install.windowsTextPost": "Modifiez les paramètres sous `output.elasticsearch` dans le fichier {path} afin de pointer vers votre installation Elasticsearch.", - "home.tutorials.common.winlogbeatInstructions.install.windowsTextPre": "Vous utilisez Winlogbeat pour la première fois ? Consultez le [guide de démarrage rapide]({winlogbeatLink}).\n 1. Téléchargez le fichier .zip Winlogbeat pour Windows via la page [Télécharger]({elasticLink}).\n 2. Extrayez le contenu du fichier compressé sous {folderPath}.\n 3. Renommez le répertoire `{directoryName}` en `Winlogbeat`.\n 4. Ouvrez une invite PowerShell en tant qu'administrateur (faites un clic droit sur l'icône PowerShell et sélectionnez **Exécuter en tant qu'administrateur**). Si vous exécutez Windows XP, vous devrez peut-être télécharger et installer PowerShell.\n 5. Dans l'invite PowerShell, exécutez les commandes suivantes afin d'installer Winlogbeat en tant que service Windows.", + "home.tutorials.common.winlogbeatInstructions.install.windowsTextPre": "Vous utilisez Winlogbeat pour la première fois ? Consultez le [guide de démarrage rapide]({winlogbeatLink}). 1. Téléchargez le fichier .zip Winlogbeat pour Windows via la page [Télécharger]({elasticLink}). 2. Extrayez le contenu du fichier compressé sous {folderPath}. 3. Renommez le répertoire `{directoryName}` en `Winlogbeat`. 4. Ouvrez une invite PowerShell en tant qu'administrateur (faites un clic droit sur l'icône PowerShell et sélectionnez **Exécuter en tant qu'administrateur**). Si vous exécutez Windows XP, vous devrez peut-être télécharger et installer PowerShell. 5. Dans l'invite PowerShell, exécutez les commandes suivantes afin d'installer Winlogbeat en tant que service Windows.", "home.tutorials.common.winlogbeatInstructions.install.windowsTitle": "Télécharger et installer Winlogbeat", "home.tutorials.common.winlogbeatInstructions.start.windowsTextPre": "La commande `setup` charge les tableaux de bord Kibana. Si les tableaux de bord sont déjà configurés, omettez cette commande.", "home.tutorials.common.winlogbeatInstructions.start.windowsTitle": "Lancer Winlogbeat", @@ -4149,7 +4652,7 @@ "home.tutorials.couchdbMetrics.nameTitle": "Indicateurs CouchDB", "home.tutorials.couchdbMetrics.shortDescription": "Collectez les indicateurs à partir des serveurs CouchDB avec Metricbeat.", "home.tutorials.crowdstrikeLogs.artifacts.dashboards.linkLabel": "Application Security", - "home.tutorials.crowdstrikeLogs.longDescription": "Il s'agit du module Filebeat pour CrowdStrike Falcon utilisant le [connecteur SIEM](https://www.crowdstrike.com/blog/tech-center/integrate-with-your-siem) Falcon. Ce module collecte ces données, les convertit en ECS et les ingère pour les afficher dans le SIEM. Par défaut, le connecteur SIEM Falcon génère les données d'événement de l'API de streaming Falcon au format JSON. [En savoir plus]({learnMoreLink}).", + "home.tutorials.crowdstrikeLogs.longDescription": "Il s'agit du module Filebeat pour CrowdStrike Falcon utilisant le [connecteur SIEM](https://www.crowdstrike.com/blog/tech-center/integrate-with-your-siem) Falcon. Ce module collecte ces données, les convertit en ECS et les ingère pour les afficher dans le SIEM. Par défaut, le connecteur SIEM Falcon génère les données d'événement de l'API de streaming Falcon au format JSON. [En savoir plus]({learnMoreLink}).", "home.tutorials.crowdstrikeLogs.nameTitle": "Logs CrowdStrike", "home.tutorials.crowdstrikeLogs.shortDescription": "Collectez et analysez les logs à partir de CrowdStrike Falcon à l'aide du Falcon SIEM Connector avec Filebeat.", "home.tutorials.cylanceLogs.artifacts.dashboards.linkLabel": "Application Security", @@ -4348,7 +4851,7 @@ "home.tutorials.o365Logs.nameTitle": "Logs Office 365", "home.tutorials.o365Logs.shortDescription": "Collectez et analysez les logs à partir d'Office 365 avec Filebeat.", "home.tutorials.oktaLogs.artifacts.dashboards.linkLabel": "Aperçu d'Okta", - "home.tutorials.oktaLogs.longDescription": "Le module Okta collecte les événements de l'[API Okta](https://developer.okta.com/docs/reference/). Plus précisément, il prend en charge la lecture depuis l'[API de log système Okta](https://developer.okta.com/docs/reference/api/system-log/). [En savoir plus]({learnMoreLink}).", + "home.tutorials.oktaLogs.longDescription": "Le module Okta collecte les événements de l'[API Okta](https://developer.okta.com/docs/reference/). Plus précisément, il prend en charge la lecture depuis l'[API de log système Okta](https://developer.okta.com/docs/reference/api/system-log/). [En savoir plus]({learnMoreLink}).", "home.tutorials.oktaLogs.nameTitle": "Logs Okta", "home.tutorials.oktaLogs.shortDescription": "Collectez et analysez les logs à partir de l'API Okta avec Filebeat.", "home.tutorials.openmetricsMetrics.longDescription": "Le module Metricbeat `openmetrics` récupère des indicateurs depuis un point de terminaison fournissant des indicateurs au format OpenMetrics. [En savoir plus]({learnMoreLink}).", @@ -4359,7 +4862,7 @@ "home.tutorials.oracleMetrics.nameTitle": "Indicateurs Oracle", "home.tutorials.oracleMetrics.shortDescription": "Collectez les indicateurs à partir de serveurs Oracle avec Metricbeat.", "home.tutorials.osqueryLogs.artifacts.dashboards.linkLabel": "Pack de conformité osquery", - "home.tutorials.osqueryLogs.longDescription": "Le module collecte et décode les logs de résultats écrits par [osqueryd](https://osquery.readthedocs.io/en/latest/introduction/using-osqueryd/) au format JSON. Pour configurer `osqueryd`, suivez les instructions d'installation d'osquery pour votre système d'exploitation et configurez le pilote de logging `filesystem` (celui par défaut). Assurez-vous que les horodatages UTC sont activés. [En savoir plus]({learnMoreLink}).", + "home.tutorials.osqueryLogs.longDescription": "Le module collecte et décode les logs de résultats écrits par [osqueryd](https://osquery.readthedocs.io/en/latest/introduction/using-osqueryd/) au format JSON. Pour configurer `osqueryd`, suivez les instructions d'installation d'osquery pour votre système d'exploitation et configurez le pilote de logging `filesystem` (celui par défaut). Assurez-vous que les horodatages UTC sont activés. [En savoir plus]({learnMoreLink}).", "home.tutorials.osqueryLogs.nameTitle": "Logs osquery", "home.tutorials.osqueryLogs.shortDescription": "Collectez et analysez les logs à partir d'Osquery avec Filebeat.", "home.tutorials.panwLogs.artifacts.dashboards.linkLabel": "Flux de réseau PANW", @@ -4423,7 +4926,7 @@ "home.tutorials.statsdMetrics.nameTitle": "Indicateurs statsd", "home.tutorials.statsdMetrics.shortDescription": "Collectez les indicateurs à partir de serveurs Statsd avec Metricbeat.", "home.tutorials.suricataLogs.artifacts.dashboards.linkLabel": "Aperçu des événements Suricata", - "home.tutorials.suricataLogs.longDescription": "Il s'agit d'un module pour le log IDS/IPS/NSM Suricata. Il analyse les logs qui sont au [format JSON Suricata Eve](https://suricata.readthedocs.io/en/latest/output/eve/eve-json-format.html). [En savoir plus]({learnMoreLink}).", + "home.tutorials.suricataLogs.longDescription": "Il s'agit d'un module pour le log IDS/IPS/NSM Suricata. Il analyse les logs qui sont au [format JSON Suricata Eve](https://suricata.readthedocs.io/en/latest/output/eve/eve-json-format.html). [En savoir plus]({learnMoreLink}).", "home.tutorials.suricataLogs.nameTitle": "Logs Suricata", "home.tutorials.suricataLogs.shortDescription": "Collectez et analysez les logs à partir de Suricata IDS/IPS/NSM avec Filebeat.", "home.tutorials.systemLogs.artifacts.dashboards.linkLabel": "Tableau de bord Syslog système", @@ -4446,7 +4949,7 @@ "home.tutorials.traefikMetrics.nameTitle": "Indicateurs Traefik", "home.tutorials.traefikMetrics.shortDescription": "Collectez les indicateurs à partir de Traefik avec Metricbeat.", "home.tutorials.uptimeMonitors.artifacts.dashboards.linkLabel": "Application Uptime", - "home.tutorials.uptimeMonitors.longDescription": "Monitorez la disponibilité des services grâce à une détection active. À partir d'une liste d'URL, Heartbeat pose cette question toute simple : Êtes-vous actif ? [En savoir plus]({learnMoreLink}).", + "home.tutorials.uptimeMonitors.longDescription": "Monitorez la disponibilité des services grâce à une détection active. À partir d'une liste d'URL, Heartbeat pose cette question toute simple : Êtes-vous actif ? [En savoir plus]({learnMoreLink}).", "home.tutorials.uptimeMonitors.nameTitle": "Monitorings Uptime", "home.tutorials.uptimeMonitors.shortDescription": "Surveillez la disponibilité des services avec Heartbeat.", "home.tutorials.uwsgiMetrics.artifacts.dashboards.linkLabel": "Tableau de bord des indicateurs uWSGI", @@ -4466,7 +4969,7 @@ "home.tutorials.windowsMetrics.nameTitle": "Indicateurs Windows", "home.tutorials.windowsMetrics.shortDescription": "Collectez les indicateurs à partir de Windows avec Metricbeat.", "home.tutorials.zeekLogs.artifacts.dashboards.linkLabel": "Aperçu de Zeek", - "home.tutorials.zeekLogs.longDescription": "Il s'agit d'un module pour Zeek, anciennement appelé Bro. Il analyse les logs qui sont au [format JSON Zeek](https://www.zeek.org/manual/release/logs/index.html). [En savoir plus]({learnMoreLink}).", + "home.tutorials.zeekLogs.longDescription": "Il s'agit d'un module pour Zeek, anciennement appelé Bro. Il analyse les logs qui sont au [format JSON Zeek](https://www.zeek.org/manual/release/logs/index.html). [En savoir plus]({learnMoreLink}).", "home.tutorials.zeekLogs.nameTitle": "Logs Zeek", "home.tutorials.zeekLogs.shortDescription": "Collectez et analysez les logs à partir de la sécurité réseau Zeek avec Filebeat.", "home.tutorials.zookeeperMetrics.artifacts.application.label": "Discover", @@ -4576,6 +5079,9 @@ "indexPatternEditor.rollup.uncaughtError": "Erreur de vue de données de cumul : {error}", "indexPatternEditor.rollupDataView.createIndex.noMatchError": "Erreur de vue de données de cumul : doit correspondre à un index de cumul", "indexPatternEditor.rollupDataView.createIndex.tooManyMatchesError": "Erreur de vue de données de cumul : ne peut correspondre qu’à un index de cumul", + "indexPatternEditor.rollupDataView.deprecationWarning.downsamplingLink": "Sous-échantillonnage", + "indexPatternEditor.rollupDataView.deprecationWarning.textParagraphOne": "Les cumuls sont obsolètes et seront supprimés dans une version ultérieure. {downsamplingLink} peut être utilisé comme solution de rechange.", + "indexPatternEditor.rollupIndexPattern.deprecationWarning.title": "Déclassé dans la version 8.11.0", "indexPatternEditor.saved": "Enregistré", "indexPatternEditor.status.matchAnyLabel.matchAnyDetail": "Votre modèle d'indexation peut correspondre à {sourceCount, plural, one {# source} other {# sources} }.", "indexPatternEditor.status.noSystemIndicesLabel": "Aucun flux de données, index ni alias d'index ne correspond à votre modèle d'indexation.", @@ -4666,7 +5172,7 @@ "indexPatternFieldEditor.editor.form.formatTitle": "Définir le format", "indexPatternFieldEditor.editor.form.nameAriaLabel": "Champ Nom", "indexPatternFieldEditor.editor.form.nameLabel": "Nom", - "indexPatternFieldEditor.editor.form.popularityDescription": "Définissez la popularité pour que le champ apparaisse plus haut ou plus bas dans la liste des champs. Par défaut, Discover classe les champs du plus souvent sélectionné au moins souvent sélectionné.", + "indexPatternFieldEditor.editor.form.popularityDescription": "Définissez la popularité pour que le champ apparaisse plus haut ou plus bas dans la liste des champs. Par défaut, Discover classe les champs du plus souvent sélectionné au moins souvent sélectionné.", "indexPatternFieldEditor.editor.form.popularityLabel": "Popularité", "indexPatternFieldEditor.editor.form.popularityTitle": "Définir la popularité", "indexPatternFieldEditor.editor.form.runtimeType.placeholderLabel": "Sélectionner un type", @@ -5070,7 +5576,7 @@ "inspector.requests.clustersTabLabel": "Clusters et partitions", "inspector.requests.copyToClipboardLabel": "Copier dans le presse-papiers", "inspector.requests.descriptionRowIconAriaLabel": "Description", - "inspector.requests.failedLabel": " (échec)", + "inspector.requests.failedLabel": "(échec)", "inspector.requests.noRequestsLoggedDescription.elementHasNotLoggedAnyRequestsText": "L'élément n'a pas (encore) consigné de requêtes.", "inspector.requests.noRequestsLoggedDescription.whatDoesItUsuallyMeanText": "Cela signifie généralement qu'il n'était pas nécessaire de récupérer des données ou que l'élément n'a pas encore commencé à récupérer des données.", "inspector.requests.noRequestsLoggedTitle": "Aucune requête consignée", @@ -5158,7 +5664,12 @@ "interactiveSetup.verificationCodeForm.submitButton": "{isSubmitting, select, true{Vérification…} other{Vérifier}}", "interactiveSetup.verificationCodeForm.submitErrorTitle": "Vérification du code impossible", "interactiveSetup.verificationCodeForm.title": "Vérification requise", + "kbn-esql-validation-autocomplete.esql.autocomplete.addDateHistogram": "Ajouter un histogramme des dates", + "kbn-esql-validation-autocomplete.esql.autocomplete.addDateHistogramDetail": "Ajouter un histogramme des dates en utilisant bucket()", + "kbn-esql-validation-autocomplete.esql.autocomplete.allStarConstantDoc": "Tous (*)", "kbn-esql-validation-autocomplete.esql.autocomplete.aPatternString": "Une chaîne modèle", + "kbn-esql-validation-autocomplete.esql.autocomplete.chooseFromTimePicker": "Cliquez pour choisir", + "kbn-esql-validation-autocomplete.esql.autocomplete.chooseFromTimePickerLabel": "Choisissez parmi le sélecteur de période", "kbn-esql-validation-autocomplete.esql.autocomplete.colonDoc": "Deux points (:)", "kbn-esql-validation-autocomplete.esql.autocomplete.commaDoc": "Virgule (,)", "kbn-esql-validation-autocomplete.esql.autocomplete.constantDefinition": "Constant", @@ -5169,11 +5680,15 @@ "kbn-esql-validation-autocomplete.esql.autocomplete.integrationDefinition": "Intégration", "kbn-esql-validation-autocomplete.esql.autocomplete.listDoc": "Liste d'éléments (…)", "kbn-esql-validation-autocomplete.esql.autocomplete.matchingFieldDefinition": "Utiliser pour correspondance avec {matchingField} de la politique", + "kbn-esql-validation-autocomplete.esql.autocomplete.namedParamDefinition": "Paramètre nommé", "kbn-esql-validation-autocomplete.esql.autocomplete.newVarDoc": "Définir une nouvelle variable", "kbn-esql-validation-autocomplete.esql.autocomplete.noPoliciesLabel": "Pas de stratégie disponible", "kbn-esql-validation-autocomplete.esql.autocomplete.noPoliciesLabelsFound": "Cliquez pour créer", "kbn-esql-validation-autocomplete.esql.autocomplete.pipeDoc": "Barre verticale (|)", "kbn-esql-validation-autocomplete.esql.autocomplete.semiColonDoc": "Point-virgule (;)", + "kbn-esql-validation-autocomplete.esql.autocomplete.sourceDefinition": "{type}", + "kbn-esql-validation-autocomplete.esql.autocomplete.timeSystemParamEnd": "L'heure de fin à partir du sélecteur de date", + "kbn-esql-validation-autocomplete.esql.autocomplete.timeSystemParamStart": "L'heure de début à partir du sélecteur de date", "kbn-esql-validation-autocomplete.esql.autocomplete.valueDefinition": "Valeur littérale", "kbn-esql-validation-autocomplete.esql.autocomplete.variableDefinition": "Variable spécifiée par l'utilisateur dans la requête ES|QL", "kbn-esql-validation-autocomplete.esql.definition.addDoc": "Ajouter (+)", @@ -5184,7 +5699,7 @@ "kbn-esql-validation-autocomplete.esql.definition.greaterThanDoc": "Supérieur à", "kbn-esql-validation-autocomplete.esql.definition.greaterThanOrEqualToDoc": "Supérieur ou égal à", "kbn-esql-validation-autocomplete.esql.definition.inDoc": "Teste si la valeur d'une expression est contenue dans une liste d'autres expressions", - "kbn-esql-validation-autocomplete.esql.definition.infoDoc": "Afficher des informations sur le nœud ES actuel", + "kbn-esql-validation-autocomplete.esql.definition.infoDoc": "Spécifier les modificateurs de tri des colonnes", "kbn-esql-validation-autocomplete.esql.definition.isNotNullDoc": "Prédicat pour la comparaison NULL : renvoie \"true\" si la valeur n'est pas NULL", "kbn-esql-validation-autocomplete.esql.definition.isNullDoc": "Prédicat pour la comparaison NULL : renvoie \"true\" si la valeur est NULL", "kbn-esql-validation-autocomplete.esql.definition.lessThanDoc": "Inférieur à", @@ -5201,13 +5716,15 @@ "kbn-esql-validation-autocomplete.esql.definitions.acos": "Renvoie l'arc cosinus de `n` sous forme d'angle, exprimé en radians.", "kbn-esql-validation-autocomplete.esql.definitions.appendSeparatorDoc": "Le ou les caractères qui séparent les champs ajoutés. A pour valeur par défaut une chaîne vide (\"\").", "kbn-esql-validation-autocomplete.esql.definitions.asDoc": "En tant que", - "kbn-esql-validation-autocomplete.esql.definitions.asin": "Renvoie l'arc sinus de l'entrée\nexpression numérique sous forme d'angle, exprimée en radians.", - "kbn-esql-validation-autocomplete.esql.definitions.atan": "Renvoie l'arc tangente de l'entrée\nexpression numérique sous forme d'angle, exprimée en radians.", - "kbn-esql-validation-autocomplete.esql.definitions.atan2": "L'angle entre l'axe positif des x et le rayon allant de\nl'origine au point (x , y) dans le plan cartésien, exprimée en radians.", + "kbn-esql-validation-autocomplete.esql.definitions.asin": "Renvoie l'arc sinus de l'expression numérique sous forme d'angle, exprimé en radians.", + "kbn-esql-validation-autocomplete.esql.definitions.atan": "Renvoie l'arc tangente de l'expression numérique sous forme d'angle, exprimé en radians.", + "kbn-esql-validation-autocomplete.esql.definitions.atan2": "L'angle entre l'axe positif des x et le rayon allant de l'origine au point (x , y) dans le plan cartésien, exprimé en radians.", "kbn-esql-validation-autocomplete.esql.definitions.autoBucketDoc": "Groupement automatique des dates en fonction d'une plage et d'un compartiment cible donnés.", + "kbn-esql-validation-autocomplete.esql.definitions.avg": "La moyenne d'un champ numérique.", "kbn-esql-validation-autocomplete.esql.definitions.byDoc": "Par", "kbn-esql-validation-autocomplete.esql.definitions.case": "Accepte les paires de conditions et de valeurs. La fonction renvoie la valeur correspondant à la première condition évaluée à `true` (vraie). Si le nombre d'arguments est impair, le dernier argument est la valeur par défaut qui est renvoyée si aucune condition ne correspond.", - "kbn-esql-validation-autocomplete.esql.definitions.cbrt": "Renvoie la racine cubique d'un nombre. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée.\nLa racine cubique de l’infini est nulle.", + "kbn-esql-validation-autocomplete.esql.definitions.categorize": "Catégorise les messages texte.", + "kbn-esql-validation-autocomplete.esql.definitions.cbrt": "Renvoie la racine cubique d'un nombre. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée. La racine cubique de l’infini est nulle.", "kbn-esql-validation-autocomplete.esql.definitions.ccqAnyDoc": "L'enrichissement a lieu sur n'importe quel cluster", "kbn-esql-validation-autocomplete.esql.definitions.ccqCoordinatorDoc": "L'enrichissement a lieu sur le cluster de coordination qui reçoit une requête ES|QL", "kbn-esql-validation-autocomplete.esql.definitions.ccqModeDoc": "Mode de requête inter-clusters", @@ -5217,8 +5734,10 @@ "kbn-esql-validation-autocomplete.esql.definitions.coalesce": "Renvoie le premier de ses arguments qui n'est pas nul. Si tous les arguments sont nuls, `null` est renvoyé.", "kbn-esql-validation-autocomplete.esql.definitions.concat": "Concatène deux ou plusieurs chaînes.", "kbn-esql-validation-autocomplete.esql.definitions.cos": "Renvoie le cosinus d'un angle.", - "kbn-esql-validation-autocomplete.esql.definitions.cosh": "Renvoie le cosinus hyperbolique d'un angle.", - "kbn-esql-validation-autocomplete.esql.definitions.date_diff": "Soustrait le `startTimestamp` du `endTimestamp` et renvoie la différence en multiples d'`unité`.\nSi `startTimestamp` est postérieur à `endTimestamp`, des valeurs négatives sont renvoyées.", + "kbn-esql-validation-autocomplete.esql.definitions.cosh": "Renvoie le cosinus hyperbolique d'un nombre.", + "kbn-esql-validation-autocomplete.esql.definitions.count": "Renvoie le nombre total de valeurs en entrée.", + "kbn-esql-validation-autocomplete.esql.definitions.count_distinct": "Renvoie le nombre approximatif de valeurs distinctes.", + "kbn-esql-validation-autocomplete.esql.definitions.date_diff": "Soustrait le `startTimestamp` du `endTimestamp` et renvoie la différence en multiples d'`unité`. Si `startTimestamp` est postérieur à `endTimestamp`, des valeurs négatives sont renvoyées.", "kbn-esql-validation-autocomplete.esql.definitions.date_extract": "Extrait des parties d'une date, telles que l'année, le mois, le jour, l'heure.", "kbn-esql-validation-autocomplete.esql.definitions.date_format": "Renvoie une représentation sous forme de chaîne d'une date dans le format fourni.", "kbn-esql-validation-autocomplete.esql.definitions.date_parse": "Renvoie une date en analysant le deuxième argument selon le format spécifié dans le premier argument.", @@ -5247,34 +5766,44 @@ "kbn-esql-validation-autocomplete.esql.definitions.ends_with": "Renvoie une valeur booléenne qui indique si une chaîne de mots-clés se termine par une autre chaîne.", "kbn-esql-validation-autocomplete.esql.definitions.enrichDoc": "Enrichissez le tableau à l'aide d'un autre tableau. Avant de pouvoir utiliser l'enrichissement, vous devez créer et exécuter une politique d'enrichissement.", "kbn-esql-validation-autocomplete.esql.definitions.evalDoc": "Calcule une expression et place la valeur résultante dans un champ de résultats de recherche.", + "kbn-esql-validation-autocomplete.esql.definitions.exp": "Renvoie la valeur de \"e\" élevée à la puissance d'un nombre donné.", "kbn-esql-validation-autocomplete.esql.definitions.floor": "Arrondir un nombre à l'entier inférieur.", "kbn-esql-validation-autocomplete.esql.definitions.from_base64": "Décodez une chaîne base64.", "kbn-esql-validation-autocomplete.esql.definitions.fromDoc": "Récupère les données à partir d'un ou plusieurs flux de données, index ou alias. Dans une requête ou une sous-requête, vous devez utiliser d'abord la commande from, et cette dernière ne nécessite pas de barre verticale au début. Par exemple, pour récupérer des données d'un index :", - "kbn-esql-validation-autocomplete.esql.definitions.greatest": "Renvoie la valeur maximale de plusieurs colonnes. Similaire à `MV_MAX`\nsauf que ceci est destiné à une exécution sur plusieurs colonnes à la fois.", + "kbn-esql-validation-autocomplete.esql.definitions.greatest": "Renvoie la valeur maximale de plusieurs colonnes. Cette fonction est similaire à `MV_MAX`. Toutefois, elle est destinée à être exécutée sur plusieurs colonnes à la fois.", "kbn-esql-validation-autocomplete.esql.definitions.grokDoc": "Extrait de multiples valeurs de chaîne à partir d'une entrée de chaîne unique, suivant un modèle", + "kbn-esql-validation-autocomplete.esql.definitions.hypot": "Renvoie l'hypoténuse de deux nombres. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée. Les hypoténuses des infinis sont nulles.", + "kbn-esql-validation-autocomplete.esql.definitions.inlineStatsDoc": "Calcule un résultat agrégé et fusionne ce résultat dans le flux de données d'entrée. Sans la clause facultative `BY`, cela produira un résultat unique qui sera ajouté à chaque ligne. Avec une clause `BY`, cela produira un résultat par regroupement et fusionnera le résultat dans le flux en fonction des clés de groupe correspondantes.", "kbn-esql-validation-autocomplete.esql.definitions.ip_prefix": "Tronque une adresse IP à une longueur de préfixe donnée.", "kbn-esql-validation-autocomplete.esql.definitions.keepDoc": "Réarrange les champs dans le tableau d'entrée en appliquant les clauses \"KEEP\" dans les champs", "kbn-esql-validation-autocomplete.esql.definitions.least": "Renvoie la valeur minimale de plusieurs colonnes. Cette fonction est similaire à `MV_MIN`. Toutefois, elle est destinée à être exécutée sur plusieurs colonnes à la fois.", "kbn-esql-validation-autocomplete.esql.definitions.left": "Renvoie la sous-chaîne qui extrait la 'longueur' des caractères de la 'chaîne' en partant de la gauche.", "kbn-esql-validation-autocomplete.esql.definitions.length": "Renvoie la longueur des caractères d'une chaîne.", "kbn-esql-validation-autocomplete.esql.definitions.limitDoc": "Renvoie les premiers résultats de recherche, dans l'ordre de recherche, en fonction de la \"limite\" spécifiée.", - "kbn-esql-validation-autocomplete.esql.definitions.locate": "Renvoie un entier qui indique la position d'une sous-chaîne de mots-clés dans une autre chaîne", - "kbn-esql-validation-autocomplete.esql.definitions.log": "Renvoie le logarithme d'une valeur dans une base. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée.\n\nLes journaux de zéros, de nombres négatifs et de base 1 renvoient `null` ainsi qu'un avertissement.", - "kbn-esql-validation-autocomplete.esql.definitions.log10": "Renvoie le logarithme d'une valeur en base 10. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée.\n\nLes logs de 0 et de nombres négatifs renvoient `null` ainsi qu'un avertissement.", + "kbn-esql-validation-autocomplete.esql.definitions.locate": "Renvoie un entier qui indique la position d'une sous-chaîne de mots-clés dans une autre chaîne. Renvoie `0` si la sous-chaîne ne peut pas être trouvée. Notez que les positions des chaînes commencent à partir de `1`.", + "kbn-esql-validation-autocomplete.esql.definitions.log": "Renvoie le logarithme d'une valeur dans une base. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée. Les journaux de zéros, de nombres négatifs et de base 1 renvoient `null` ainsi qu'un avertissement.", + "kbn-esql-validation-autocomplete.esql.definitions.log10": "Renvoie le logarithme d'une valeur en base 10. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée. Les logs de 0 et de nombres négatifs renvoient `null` ainsi qu'un avertissement.", "kbn-esql-validation-autocomplete.esql.definitions.ltrim": "Retire les espaces au début des chaînes.", + "kbn-esql-validation-autocomplete.esql.definitions.max": "La valeur maximale d'un champ.", + "kbn-esql-validation-autocomplete.esql.definitions.median": "La valeur qui est supérieure à la moitié de toutes les valeurs et inférieure à la moitié de toutes les valeurs, également connue sous le nom de `PERCENTILE` 50.", + "kbn-esql-validation-autocomplete.esql.definitions.median_absolute_deviation": "Renvoie l'écart absolu médian, une mesure de la variabilité. Il s'agit d'un indicateur robuste, ce qui signifie qu'il est utile pour décrire des données qui peuvent présenter des valeurs aberrantes ou ne pas être normalement distribuées. Pour de telles données, il peut être plus descriptif que l'écart-type. Il est calculé comme la médiane de chaque écart de point de données par rapport à la médiane de l'ensemble de l'échantillon. Autrement dit, pour une variable aléatoire `X`, l'écart absolu médian est `median(|median(X) - X|)`.", "kbn-esql-validation-autocomplete.esql.definitions.metadataDoc": "Métadonnées", "kbn-esql-validation-autocomplete.esql.definitions.metricsDoc": "Une commande source spécifique aux indicateurs, utilisez-la pour charger des données à partir des index de TSDB. Similaire à la commande STATS : calcule les statistiques agrégées, telles que la moyenne, le décompte et la somme, sur l'ensemble des résultats de recherche entrants. Si elle est utilisée sans clause BY, une seule ligne est renvoyée, qui est l'agrégation de tout l'ensemble des résultats de recherche entrants. Lorsque vous utilisez une clause BY, une ligne est renvoyée pour chaque valeur distincte dans le champ spécifié dans la clause BY. La commande renvoie uniquement les champs dans l'agrégation, et vous pouvez utiliser un large éventail de fonctions statistiques avec la commande stats. Lorsque vous effectuez plusieurs agrégations, séparez chacune d'entre elle par une virgule.", + "kbn-esql-validation-autocomplete.esql.definitions.min": "La valeur minimale d'un champ.", "kbn-esql-validation-autocomplete.esql.definitions.mv_append": "Concatène les valeurs de deux champs à valeurs multiples.", "kbn-esql-validation-autocomplete.esql.definitions.mv_avg": "Convertit un champ multivalué en un champ à valeur unique comprenant la moyenne de toutes les valeurs.", "kbn-esql-validation-autocomplete.esql.definitions.mv_concat": "Convertit une expression de type chaîne multivalué en une colonne à valeur unique comprenant la concaténation de toutes les valeurs, séparées par un délimiteur.", "kbn-esql-validation-autocomplete.esql.definitions.mv_count": "Convertit une expression multivaluée en une colonne à valeur unique comprenant le total du nombre de valeurs.", "kbn-esql-validation-autocomplete.esql.definitions.mv_dedupe": "Supprime les valeurs en doublon d'un champ multivalué.", - "kbn-esql-validation-autocomplete.esql.definitions.mv_first": "Convertit une expression multivaluée en une colonne à valeur unique comprenant la\npremière valeur. Ceci est particulièrement utile pour lire une fonction qui émet\ndes colonnes multivaluées dans un ordre connu, comme `SPLIT`.\n\nL'ordre dans lequel les champs multivalués sont lus à partir\ndu stockage sous-jacent n'est pas garanti. Il est *souvent* ascendant, mais ne vous y\nfiez pas. Si vous avez besoin de la valeur minimale, utilisez `MV_MIN` au lieu de\n`MV_FIRST`. `MV_MIN` comporte des optimisations pour les valeurs triées, il n'y a donc aucun\navantage en matière de performances pour `MV_FIRST`.", - "kbn-esql-validation-autocomplete.esql.definitions.mv_last": "Convertit une expression multivaluée en une colonne à valeur unique comprenant la dernière\nvaleur. Ceci est particulièrement utile pour lire une fonction qui émet des champs multivalués\ndans un ordre connu, comme `SPLIT`.\n\nL'ordre dans lequel les champs multivalués sont lus à partir\ndu stockage sous-jacent n'est pas garanti. Il est *souvent* ascendant, mais ne vous y\nfiez pas. Si vous avez besoin de la valeur maximale, utilisez `MV_MAX` au lieu de\n`MV_LAST`. `MV_MAX` comporte des optimisations pour les valeurs triées, il n'y a donc aucun\navantage en matière de performances pour `MV_LAST`.", + "kbn-esql-validation-autocomplete.esql.definitions.mv_first": "Convertit une expression multivaluée en une colonne à valeur unique comprenant la première valeur. Ceci est particulièrement utile pour lire une fonction qui émet des colonnes multivaluées dans un ordre connu, comme `SPLIT`.", + "kbn-esql-validation-autocomplete.esql.definitions.mv_last": "Convertit une expression multivaluée en une colonne à valeur unique comprenant la dernière valeur. Ceci est particulièrement utile pour lire une fonction qui émet des colonnes multivaluées dans un ordre connu, comme `SPLIT`.", "kbn-esql-validation-autocomplete.esql.definitions.mv_max": "Convertit une expression multivaluée en une colonne à valeur unique comprenant la valeur maximale.", "kbn-esql-validation-autocomplete.esql.definitions.mv_median": "Convertit un champ multivalué en un champ à valeur unique comprenant la valeur médiane.", + "kbn-esql-validation-autocomplete.esql.definitions.mv_median_absolute_deviation": "Convertit un champ multivalué en un champ à valeur unique comprenant l'écart absolu médian. Il est calculé comme la médiane de chaque écart de point de données par rapport à la médiane de l'ensemble de l'échantillon. Autrement dit, pour une variable aléatoire `X`, l'écart absolu médian est `median(|median(X) - X|)`.", "kbn-esql-validation-autocomplete.esql.definitions.mv_min": "Convertit une expression multivaluée en une colonne à valeur unique comprenant la valeur minimale.", - "kbn-esql-validation-autocomplete.esql.definitions.mv_slice": "Renvoie un sous-ensemble du champ multivalué en utilisant les valeurs d'index de début et de fin.", + "kbn-esql-validation-autocomplete.esql.definitions.mv_percentile": "Convertit un champ multivalué en un champ à valeur unique comprenant la valeur à laquelle un certain pourcentage des valeurs observées se produit.", + "kbn-esql-validation-autocomplete.esql.definitions.mv_pseries_weighted_sum": "Convertit une expression multivaluée en une colonne à valeur unique en multipliant chaque élément de la liste d'entrée par le terme correspondant dans P-Series et en calculant la somme.", + "kbn-esql-validation-autocomplete.esql.definitions.mv_slice": "Renvoie un sous-ensemble du champ multivalué en utilisant les valeurs d'index de début et de fin. Ceci est particulièrement utile pour lire une fonction qui émet des colonnes multivaluées dans un ordre connu, comme `SPLIT` ou `MV_SORT`.", "kbn-esql-validation-autocomplete.esql.definitions.mv_sort": "Trie une expression multivaluée par ordre lexicographique.", "kbn-esql-validation-autocomplete.esql.definitions.mv_sum": "Convertit un champ multivalué en un champ à valeur unique comprenant la somme de toutes les valeurs.", "kbn-esql-validation-autocomplete.esql.definitions.mv_zip": "Combine les valeurs de deux champs multivalués avec un délimiteur qui les relie.", @@ -5283,53 +5812,63 @@ "kbn-esql-validation-autocomplete.esql.definitions.onDoc": "Activé", "kbn-esql-validation-autocomplete.esql.definitions.pi": "Renvoie Pi, le rapport entre la circonférence et le diamètre d'un cercle.", "kbn-esql-validation-autocomplete.esql.definitions.pow": "Renvoie la valeur d’une `base` élevée à la puissance d’un `exposant`.", + "kbn-esql-validation-autocomplete.esql.definitions.qstr": "Exécute une requête de chaîne de requête. Renvoie true si la chaîne de requête fournie correspond à la ligne.", "kbn-esql-validation-autocomplete.esql.definitions.renameDoc": "Attribue un nouveau nom à une ancienne colonne", "kbn-esql-validation-autocomplete.esql.definitions.repeat": "Renvoie une chaîne construite par la concaténation de la `chaîne` avec elle-même, le `nombre` de fois spécifié.", - "kbn-esql-validation-autocomplete.esql.definitions.replace": "La fonction remplace dans la chaîne `str` toutes les correspondances avec l'expression régulière `regex`\npar la chaîne de remplacement `newStr`.", - "kbn-esql-validation-autocomplete.esql.definitions.right": "Renvoie la sous-chaîne qui extrait la 'longueur' des caractères de 'str' en partant de la droite.", - "kbn-esql-validation-autocomplete.esql.definitions.round": "Arrondit un nombre au nombre spécifié de décimales.\nLa valeur par défaut est 0, qui renvoie l'entier le plus proche. Si le\nnombre de décimales spécifié est négatif, la fonction arrondit au nombre de décimales à gauche\nde la virgule.", + "kbn-esql-validation-autocomplete.esql.definitions.replace": "La fonction remplace dans la chaîne `str` toutes les correspondances avec l'expression régulière `regex` par la chaîne de remplacement `newStr`.", + "kbn-esql-validation-autocomplete.esql.definitions.reverse": "Renvoie une nouvelle chaîne représentant la chaîne d'entrée dans l'ordre inverse.", + "kbn-esql-validation-autocomplete.esql.definitions.right": "Renvoie la sous-chaîne qui extrait la longueur des caractères de `str` en partant de la droite.", + "kbn-esql-validation-autocomplete.esql.definitions.round": "Arrondit un nombre au nombre spécifié de décimales. La valeur par défaut est 0, qui renvoie l'entier le plus proche. Si le nombre de décimales spécifié est négatif, la fonction arrondit au nombre de décimales à gauche.", "kbn-esql-validation-autocomplete.esql.definitions.rowDoc": "Renvoie une ligne contenant une ou plusieurs colonnes avec les valeurs que vous spécifiez. Cette commande peut s'avérer utile pour les tests.", "kbn-esql-validation-autocomplete.esql.definitions.rtrim": "Supprime les espaces à la fin des chaînes.", "kbn-esql-validation-autocomplete.esql.definitions.showDoc": "Renvoie des informations sur le déploiement et ses capacités", - "kbn-esql-validation-autocomplete.esql.definitions.signum": "Renvoie le signe du nombre donné.\nRenvoie `-1` pour les nombres négatifs, `0` pour `0` et `1` pour les nombres positifs.", - "kbn-esql-validation-autocomplete.esql.definitions.sin": "Renvoie la fonction trigonométrique sinusoïdale d'un angle.", - "kbn-esql-validation-autocomplete.esql.definitions.sinh": "Renvoie le sinus hyperbolique d'un angle.", + "kbn-esql-validation-autocomplete.esql.definitions.signum": "Renvoie le signe du nombre donné. Renvoie `-1` pour les nombres négatifs, `0` pour `0` et `1` pour les nombres positifs.", + "kbn-esql-validation-autocomplete.esql.definitions.sin": "Renvoie le sinus d'un angle.", + "kbn-esql-validation-autocomplete.esql.definitions.sinh": "Renvoie le sinus hyperbolique d'un nombre.", "kbn-esql-validation-autocomplete.esql.definitions.sortDoc": "Trie tous les résultats en fonction des champs spécifiés. Par défaut, les valeurs null sont considérées comme supérieures à toutes les autres valeurs. Avec l'ordre de tri croissant, les valeurs null sont classées en dernier. Avec l'ordre de tri décroissant, elles sont classées en premier. Pour modifier cet ordre, utilisez NULLS FIRST ou NULLS LAST", + "kbn-esql-validation-autocomplete.esql.definitions.space": "Renvoie une chaîne composée d'espaces nombre (`number`).", "kbn-esql-validation-autocomplete.esql.definitions.split": "Divise une chaîne de valeur unique en plusieurs chaînes.", - "kbn-esql-validation-autocomplete.esql.definitions.sqrt": "Renvoie la racine carrée d'un nombre. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée.\nLes racines carrées des nombres négatifs et des infinis sont nulles.", - "kbn-esql-validation-autocomplete.esql.definitions.st_contains": "Renvoie si la première géométrie contient la deuxième géométrie.\nIl s'agit de l'inverse de la fonction `ST_WITHIN`.", - "kbn-esql-validation-autocomplete.esql.definitions.st_disjoint": "Renvoie si les deux géométries ou colonnes géométriques sont disjointes.\nIl s'agit de l'inverse de la fonction `ST_INTERSECTS`.\nEn termes mathématiques : ST_Disjoint(A, B) ⇔ A ⋂ B = ∅", - "kbn-esql-validation-autocomplete.esql.definitions.st_distance": "Calcule la distance entre deux points.\nPour les géométries cartésiennes, c’est la distance pythagoricienne dans les mêmes unités que les coordonnées d'origine.\nPour les géométries géographiques, c’est la distance circulaire le long du grand cercle en mètres.", - "kbn-esql-validation-autocomplete.esql.definitions.st_intersects": "Renvoie `true` (vrai) si deux géométries se croisent.\nElles se croisent si elles ont un point commun, y compris leurs points intérieurs\n(les points situés le long des lignes ou dans des polygones).\nIl s'agit de l'inverse de la fonction `ST_DISJOINT`.\nEn termes mathématiques : ST_Intersects(A, B) ⇔ A ⋂ B ≠ ∅", - "kbn-esql-validation-autocomplete.esql.definitions.st_within": "Renvoie si la première géométrie est à l'intérieur de la deuxième géométrie.\nIl s'agit de l'inverse de la fonction `ST_CONTAINS`.", - "kbn-esql-validation-autocomplete.esql.definitions.st_x": "Extrait la coordonnée `x` du point fourni.\nSi les points sont de type `geo_point`, cela revient à extraire la valeur de la `longitude`.", - "kbn-esql-validation-autocomplete.esql.definitions.st_y": "Extrait la coordonnée `y` du point fourni.\nSi les points sont de type `geo_point`, cela revient à extraire la valeur de la `latitude`.", + "kbn-esql-validation-autocomplete.esql.definitions.sqrt": "Renvoie la racine carrée d'un nombre. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée. Les racines carrées des nombres négatifs et des infinis sont nulles.", + "kbn-esql-validation-autocomplete.esql.definitions.st_centroid_agg": "Calcule le centroïde spatial sur un champ avec un type de géométrie de point spatial.", + "kbn-esql-validation-autocomplete.esql.definitions.st_contains": "Renvoie si la première géométrie contient la deuxième géométrie. Il s'agit de l'inverse de la fonction `ST_WITHIN`.", + "kbn-esql-validation-autocomplete.esql.definitions.st_disjoint": "Renvoie si les deux géométries ou colonnes géométriques sont disjointes. Il s'agit de l'inverse de la fonction `ST_INTERSECTS`. En termes mathématiques : ST_Disjoint(A, B) ⇔ A ⋂ B = ∅", + "kbn-esql-validation-autocomplete.esql.definitions.st_distance": "Calcule la distance entre deux points. Pour les géométries cartésiennes, c’est la distance pythagoricienne dans les mêmes unités que les coordonnées d'origine. Pour les géométries géographiques, c’est la distance circulaire le long du grand cercle en mètres.", + "kbn-esql-validation-autocomplete.esql.definitions.st_intersects": "Renvoie `true` (vrai) si deux géométries se croisent. Elles se croisent si elles ont un point commun, y compris leurs points intérieurs (points le long de lignes ou à l'intérieur de polygones). Il s'agit de l'inverse de la fonction `ST_DISJOINT`. En termes mathématiques : ST_Intersects(A, B) ⇔ A ⋂ B ≠ ∅", + "kbn-esql-validation-autocomplete.esql.definitions.st_within": "Renvoie si la première géométrie est à l'intérieur de la deuxième géométrie. Il s'agit de l'inverse de la fonction `ST_CONTAINS`.", + "kbn-esql-validation-autocomplete.esql.definitions.st_x": "Extrait la coordonnée `x` du point fourni. Si les points sont de type `geo_point`, cela revient à extraire la valeur de la `longitude`.", + "kbn-esql-validation-autocomplete.esql.definitions.st_y": "Extrait la coordonnée `y` du point fourni. Si les points sont de type `geo_point`, cela revient à extraire la valeur de la `latitude`.", "kbn-esql-validation-autocomplete.esql.definitions.starts_with": "Renvoie un booléen qui indique si une chaîne de mot-clés débute par une autre chaîne.", "kbn-esql-validation-autocomplete.esql.definitions.statsDoc": "Calcule les statistiques agrégées, telles que la moyenne, le décompte et la somme, sur l'ensemble des résultats de recherche entrants. Comme pour l'agrégation SQL, si la commande stats est utilisée sans clause BY, une seule ligne est renvoyée, qui est l'agrégation de tout l'ensemble des résultats de recherche entrants. Lorsque vous utilisez une clause BY, une ligne est renvoyée pour chaque valeur distincte dans le champ spécifié dans la clause BY. La commande stats renvoie uniquement les champs dans l'agrégation, et vous pouvez utiliser un large éventail de fonctions statistiques avec la commande stats. Lorsque vous effectuez plusieurs agrégations, séparez chacune d'entre elle par une virgule.", - "kbn-esql-validation-autocomplete.esql.definitions.substring": "Renvoie la sous-chaîne d'une chaîne, délimitée en fonction d'une position de départ et d'une longueur facultative", - "kbn-esql-validation-autocomplete.esql.definitions.tan": "Renvoie la fonction trigonométrique Tangente d'un angle.", - "kbn-esql-validation-autocomplete.esql.definitions.tanh": "Renvoie la fonction hyperbolique Tangente d'un angle.", + "kbn-esql-validation-autocomplete.esql.definitions.substring": "Renvoie la sous-chaîne d'une chaîne, délimitée en fonction d'une position de départ et d'une longueur facultative.", + "kbn-esql-validation-autocomplete.esql.definitions.sum": "La somme d'une expression numérique.", + "kbn-esql-validation-autocomplete.esql.definitions.tan": "Renvoie la tangente d'un angle.", + "kbn-esql-validation-autocomplete.esql.definitions.tanh": "Renvoie la tangente hyperbolique d'un nombre.", "kbn-esql-validation-autocomplete.esql.definitions.tau": "Renvoie le rapport entre la circonférence et le rayon d'un cercle.", "kbn-esql-validation-autocomplete.esql.definitions.to_base64": "Encode une chaîne en chaîne base64.", - "kbn-esql-validation-autocomplete.esql.definitions.to_boolean": "Convertit une valeur d'entrée en une valeur booléenne.\nUne chaîne de valeur *true* sera convertie, sans tenir compte de la casse, en une valeur booléenne *true*.\nPour toute autre valeur, y compris une chaîne vide, la fonction renverra *false*.\nLa valeur numérique *0* sera convertie en *false*, toute autre valeur sera convertie en *true*.", - "kbn-esql-validation-autocomplete.esql.definitions.to_cartesianpoint": "Convertit la valeur d'une entrée en une valeur `cartesian_point`.\nUne chaîne ne sera convertie avec succès que si elle respecte le format WKT Point.", - "kbn-esql-validation-autocomplete.esql.definitions.to_cartesianshape": "Convertit une valeur d'entrée en une valeur `cartesian_shape`.\nUne chaîne ne sera convertie avec succès que si elle respecte le format WKT.", - "kbn-esql-validation-autocomplete.esql.definitions.to_datetime": "Convertit une valeur d'entrée en une valeur de date.\nUne chaîne ne sera convertie efficacement que si elle respecte le format `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'`.\nPour convertir des dates vers d'autres formats, utilisez `DATE_PARSE`.", + "kbn-esql-validation-autocomplete.esql.definitions.to_boolean": "Convertit une valeur d'entrée en une valeur booléenne. Une chaîne de valeur *true* sera convertie, sans tenir compte de la casse, en une valeur booléenne *true*. Pour toute autre valeur, y compris une chaîne vide, la fonction renverra *false*. La valeur numérique *0* sera convertie en *false*, toute autre valeur sera convertie en *true*.", + "kbn-esql-validation-autocomplete.esql.definitions.to_cartesianpoint": "Convertit la valeur d'une entrée en une valeur `cartesian_point`. Une chaîne ne sera convertie avec succès que si elle respecte le format WKT Point.", + "kbn-esql-validation-autocomplete.esql.definitions.to_cartesianshape": "Convertit une valeur d'entrée en une valeur `cartesian_shape`. Une chaîne ne sera convertie que si elle respecte le format WKT.", + "kbn-esql-validation-autocomplete.esql.definitions.to_date_nanos": "Convertit une entrée en une valeur de date de résolution nanoseconde (ou date_nanos).", + "kbn-esql-validation-autocomplete.esql.definitions.to_dateperiod": "Convertit une valeur d'entrée en une valeur `date_period`.", + "kbn-esql-validation-autocomplete.esql.definitions.to_datetime": "Convertit une valeur d'entrée en une valeur de date. Une chaîne ne sera convertie que si elle respecte le format `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'`. Pour convertir des dates vers d'autres formats, utilisez `DATE_PARSE`.", "kbn-esql-validation-autocomplete.esql.definitions.to_degrees": "Convertit un nombre en radians en degrés.", - "kbn-esql-validation-autocomplete.esql.definitions.to_double": "Convertit une valeur d'entrée en une valeur double. Si le paramètre d'entrée est de type date,\nsa valeur sera interprétée en millisecondes depuis l'heure Unix,\nconvertie en double. Le booléen *true* sera converti en double *1.0*, et *false* en *0.0*.", - "kbn-esql-validation-autocomplete.esql.definitions.to_geopoint": "Convertit une valeur d'entrée en une valeur `geo_point`.\nUne chaîne ne sera convertie avec succès que si elle respecte le format WKT Point.", - "kbn-esql-validation-autocomplete.esql.definitions.to_geoshape": "Convertit une valeur d'entrée en une valeur `geo_shape`.\nUne chaîne ne sera convertie avec succès que si elle respecte le format WKT.", - "kbn-esql-validation-autocomplete.esql.definitions.to_integer": "Convertit une valeur d'entrée en une valeur entière.\nSi le paramètre d'entrée est de type date, sa valeur sera interprétée en millisecondes\ndepuis l'heure Unix, convertie en entier.\nLe booléen *true* sera converti en entier *1*, et *false* en *0*.", + "kbn-esql-validation-autocomplete.esql.definitions.to_double": "Convertit une valeur d'entrée en une valeur double. Si le paramètre d'entrée est de type date, sa valeur sera interprétée en millisecondes depuis l'heure Unix, convertie en double. Le booléen *true* sera converti en double *1.0*, et *false* en *0.0*.", + "kbn-esql-validation-autocomplete.esql.definitions.to_geopoint": "Convertit une valeur d'entrée en une valeur `geo_point`. Une chaîne ne sera convertie avec succès que si elle respecte le format WKT Point.", + "kbn-esql-validation-autocomplete.esql.definitions.to_geoshape": "Convertit une valeur d'entrée en une valeur `geo_shape`. Une chaîne ne sera convertie avec succès que si elle respecte le format WKT.", + "kbn-esql-validation-autocomplete.esql.definitions.to_integer": "Convertit une valeur d'entrée en une valeur entière. Si le paramètre d'entrée est de type date, sa valeur sera interprétée en millisecondes depuis l'heure Unix, convertie en nombre entier. Le booléen *true* sera converti en entier *1*, et *false* en *0*.", "kbn-esql-validation-autocomplete.esql.definitions.to_ip": "Convertit une chaîne d'entrée en valeur IP.", - "kbn-esql-validation-autocomplete.esql.definitions.to_long": "Convertit une valeur d'entrée en une valeur longue. Si le paramètre d'entrée est de type date,\nsa valeur sera interprétée en millisecondes depuis l'heure Unix, convertie en valeur longue.\nLe booléen *true* sera converti en valeur longue *1*, et *false* en *0*.", + "kbn-esql-validation-autocomplete.esql.definitions.to_long": "Convertit une valeur d'entrée en une valeur longue. Si le paramètre d'entrée est de type date, sa valeur sera interprétée en millisecondes depuis l'heure Unix, convertie en valeur longue. Le booléen *true* sera converti en valeur longue *1*, et *false* en *0*.", "kbn-esql-validation-autocomplete.esql.definitions.to_lower": "Renvoie une nouvelle chaîne représentant la chaîne d'entrée convertie en minuscules.", "kbn-esql-validation-autocomplete.esql.definitions.to_radians": "Convertit un nombre en degrés en radians.", "kbn-esql-validation-autocomplete.esql.definitions.to_string": "Convertit une valeur d'entrée en une chaîne.", - "kbn-esql-validation-autocomplete.esql.definitions.to_unsigned_long": "Convertit une valeur d'entrée en une valeur longue non signée. Si le paramètre d'entrée est de type date,\nsa valeur sera interprétée en millisecondes depuis l'heure Unix, convertie en valeur longue non signée.\nLe booléen *true* sera converti en valeur longue non signée *1*, et *false* en *0*.", + "kbn-esql-validation-autocomplete.esql.definitions.to_timeduration": "Convertit une valeur d'entrée en valeur `time_duration`.", + "kbn-esql-validation-autocomplete.esql.definitions.to_unsigned_long": "Convertit une valeur d'entrée en une valeur longue non signée. Si le paramètre d'entrée est de type date, sa valeur sera interprétée en millisecondes depuis l'heure Unix, convertie en valeur longue non signée. Le booléen *true* sera converti en valeur longue non signée *1*, et *false* en *0*.", "kbn-esql-validation-autocomplete.esql.definitions.to_upper": "Renvoie une nouvelle chaîne représentant la chaîne d'entrée convertie en majuscules.", "kbn-esql-validation-autocomplete.esql.definitions.to_version": "Convertit une chaîne d'entrée en une valeur de version.", + "kbn-esql-validation-autocomplete.esql.definitions.top": "Collecte les valeurs les plus hautes d'un champ. Inclut les valeurs répétées.", "kbn-esql-validation-autocomplete.esql.definitions.trim": "Supprime les espaces de début et de fin d'une chaîne.", - "kbn-esql-validation-autocomplete.esql.definitions.values": "Renvoie toutes les valeurs d'un groupe dans un tableau.", + "kbn-esql-validation-autocomplete.esql.definitions.values": "Renvoie toutes les valeurs d’un groupe dans un champ multivalué. L'ordre des valeurs renvoyées n'est pas garanti. Si vous avez besoin que les valeurs renvoyées soient dans l'ordre, utilisez `esql-mv_sort`.", + "kbn-esql-validation-autocomplete.esql.definitions.weighted_avg": "La moyenne pondérée d'une expression numérique.", "kbn-esql-validation-autocomplete.esql.definitions.whereDoc": "Utilise \"predicate-expressions\" pour filtrer les résultats de recherche. Une expression predicate, lorsqu'elle est évaluée, renvoie TRUE ou FALSE. La commande where renvoie uniquement les résultats qui donnent la valeur TRUE. Par exemple, pour filtrer les résultats pour une valeur de champ spécifique", "kbn-esql-validation-autocomplete.esql.definitions.withDoc": "Avec", "kbn-esql-validation-autocomplete.esql.divide.warning.divideByZero": "Impossible de diviser par zéro : {left}/{right}", @@ -5346,7 +5885,10 @@ "kbn-esql-validation-autocomplete.esql.validation.metadataBracketsDeprecation": "Les crochets \"[]\" doivent être supprimés de la déclaration FROM METADATA", "kbn-esql-validation-autocomplete.esql.validation.missingFunction": "Fonction inconnue [{name}]", "kbn-esql-validation-autocomplete.esql.validation.noAggFunction": "Au moins une fonction d'agrégation requise dans [{command}], [{expression}] trouvée", + "kbn-esql-validation-autocomplete.esql.validation.noCombinationOfAggAndNonAggValues": "Impossible de combiner les valeurs agrégées et non agrégées dans [{commandName}], [{expression}] trouvée", "kbn-esql-validation-autocomplete.esql.validation.noNestedArgumentSupport": "Les paramètres de la fonction agrégée doivent être un attribut, un littéral ou une fonction non agrégée ; trouvé [{name}] de type [{argType}]", + "kbn-esql-validation-autocomplete.esql.validation.statsNoAggFunction": "Au moins une fonction d'agrégation requise dans [{commandName}], [{expression}] trouvée", + "kbn-esql-validation-autocomplete.esql.validation.statsNoArguments": "[{commandName}] doit contenir au moins une expression d'agrégation ou de regroupement", "kbn-esql-validation-autocomplete.esql.validation.typeOverwrite": "La colonne [{field}] de type {fieldType} a été écrasée par un nouveau type : {newType}", "kbn-esql-validation-autocomplete.esql.validation.unknowAggregateFunction": "Attendait une fonction ou un groupe agrégé mais a obtenu [{value}] de type [{type}]", "kbn-esql-validation-autocomplete.esql.validation.unknownColumn": "Colonne inconnue[{name}]", @@ -5371,6 +5913,18 @@ "kbn-esql-validation-autocomplete.esql.validation.wrongArgumentType": "L'argument de [{name}] doit être [{argType}], valeur [{value}] trouvée de type [{givenType}]", "kbn-esql-validation-autocomplete.esql.validation.wrongDissectOptionArgumentType": "Valeur non valide pour DISSECT append_separator : une chaîne était attendue mais il s'agissait de [{value}]", "kbn-esql-validation-autocomplete.esql.validation.wrongMetadataArgumentType": "Le champ de métadonnées [{value}] n'est pas disponible. Les champs de métadonnées disponibles sont : [{availableFields}]", + "kbn-esql-validation-autocomplete.recommendedQueries.aggregateExample.description": "Agrégation des quantités", + "kbn-esql-validation-autocomplete.recommendedQueries.aggregateExample.label": "Agréger avec STATS", + "kbn-esql-validation-autocomplete.recommendedQueries.caseExample.description": "Conditionnel", + "kbn-esql-validation-autocomplete.recommendedQueries.caseExample.label": "Créer un élément conditionnel avec CASE", + "kbn-esql-validation-autocomplete.recommendedQueries.dateHistogram.description": "Agrégation des totaux au fil du temps", + "kbn-esql-validation-autocomplete.recommendedQueries.dateHistogram.label": "Créer un histogramme de date", + "kbn-esql-validation-autocomplete.recommendedQueries.dateIntervals.description": "Agrégation des totaux au fil du temps", + "kbn-esql-validation-autocomplete.recommendedQueries.dateIntervals.label": "Créez des intervalles de temps de 5 minutes avec EVAL", + "kbn-esql-validation-autocomplete.recommendedQueries.lastHour.description": "Un exemple plus complexe", + "kbn-esql-validation-autocomplete.recommendedQueries.lastHour.label": "Nombre total par rapport au nombre de la dernière heure", + "kbn-esql-validation-autocomplete.recommendedQueries.sortByTime.description": "Trier par heure", + "kbn-esql-validation-autocomplete.recommendedQueries.sortByTime.label": "Trier par heure", "kbnConfig.deprecations.conflictSetting.manualStepOneMessage": "Assurez-vous que \"{fullNewPath}\" contient la valeur correcte dans le fichier de configuration, l'indicateur CLI ou la variable d'environnement (dans Docker uniquement).", "kbnConfig.deprecations.conflictSetting.manualStepTwoMessage": "Supprimez \"{fullOldPath}\" de la configuration.", "kbnConfig.deprecations.conflictSettingMessage": "Le paramètre \"{fullOldPath}\" a été remplacé par \"{fullNewPath}\". Cependant, les deux clés sont présentes. Ignorer \"{fullOldPath}\"", @@ -5381,9 +5935,10 @@ "kbnConfig.deprecations.replacedSettingMessage": "Le paramètre \"{fullOldPath}\" a été remplacé par \"{fullNewPath}\".", "kbnConfig.deprecations.unusedSetting.manualStepOneMessage": "Retirez \"{fullPath}\" dans le fichier de configuration Kibana, l'indicateur CLI ou la variable d'environnement (dans Docker uniquement).", "kbnConfig.deprecations.unusedSettingMessage": "Vous n’avez plus besoin de configurer \"{fullPath}\".", + "kbnGridLayout.row.toggleCollapse": "Basculer vers la réduction", "kibana_utils.history.savedObjectIsMissingNotificationMessage": "L'objet enregistré est manquant.", "kibana_utils.stateManagement.stateHash.unableToRestoreUrlErrorMessage": "Impossible de restaurer complètement l'URL. Assurez-vous d'utiliser la fonctionnalité de partage.", - "kibana_utils.stateManagement.stateHash.unableToStoreHistoryInSessionErrorMessage": "Kibana n'est pas en mesure de stocker des éléments d'historique dans votre session, car le stockage est arrivé à saturation et il ne semble pas y avoir d'éléments pouvant être supprimés sans risque.\n\nCe problème peut généralement être corrigé en passant à un nouvel onglet, mais il peut être causé par un problème plus important. Si ce message s'affiche régulièrement, veuillez nous en faire part sur {gitHubIssuesUrl}.", + "kibana_utils.stateManagement.stateHash.unableToStoreHistoryInSessionErrorMessage": "Kibana n'est pas en mesure de stocker des éléments d'historique dans votre session, car le stockage est arrivé à saturation et il ne semble pas y avoir d'éléments pouvant être supprimés sans risque. Ce problème peut généralement être corrigé en passant à un nouvel onglet, mais il peut être causé par un problème plus important. Si ce message s'affiche régulièrement, veuillez nous en faire part sur {gitHubIssuesUrl}.", "kibana_utils.stateManagement.url.restoreUrlErrorTitle": "Erreur lors de la restauration de l'état depuis l'URL.", "kibana_utils.stateManagement.url.saveStateInUrlErrorTitle": "Erreur lors de l'enregistrement de l'état dans l'URL.", "kibana-react.dualRangeControl.maxInputAriaLabel": "Maximum de la plage", @@ -5422,263 +5977,315 @@ "kibanaOverview.more.title": "Toujours plus avec Elastic", "kibanaOverview.news.title": "Nouveautés", "languageDocumentation.documentationESQL.abs": "ABS", - "languageDocumentation.documentationESQL.abs.markdown": "\n\n ### ABS\n Renvoie la valeur absolue.\n\n ````\n Numéro ROW = -1.0 \n | EVAL abs_number = ABS(number)\n ````\n ", + "languageDocumentation.documentationESQL.abs.markdown": " ### ABS Renvoie la valeur absolue. ``` ROW number = -1.0 | EVAL abs_number = ABS(number) ```", "languageDocumentation.documentationESQL.acos": "ACOS", - "languageDocumentation.documentationESQL.acos.markdown": "\n\n ### ACOS\n Renvoie l'arc cosinus de `n` sous forme d'angle, exprimé en radians.\n\n ````\n ROW a=.9\n | EVAL acos=ACOS(a)\n ````\n ", + "languageDocumentation.documentationESQL.acos.markdown": " ### ACOS Renvoie l'arc cosinus de `n` sous forme d'angle, exprimé en radians. ``` ROW a=.9 | EVAL acos=ACOS(a) ```", "languageDocumentation.documentationESQL.aggregationFunctions": "Fonctions d'agrégation", "languageDocumentation.documentationESQL.aggregationFunctionsDocumentationESQLDescription": "Ces fonctions peuvent être utilisées avec STATS...BY :", "languageDocumentation.documentationESQL.asin": "ASIN", - "languageDocumentation.documentationESQL.asin.markdown": "\n\n ### ASIN\n Renvoie l'arc sinus de l'entrée\n expression numérique sous forme d'angle, exprimée en radians.\n\n ````\n ROW a=.9\n | EVAL asin=ASIN(a)\n ````\n ", + "languageDocumentation.documentationESQL.asin.markdown": " ### ASIN Renvoie l'arc sinus de l'expression numérique sous forme d'angle, exprimé en radians. ``` ROW a=.9 | EVAL asin=ASIN(a) ```", "languageDocumentation.documentationESQL.atan": "ATAN", - "languageDocumentation.documentationESQL.atan.markdown": "\n\n ### ATAN\n Renvoie l'arc tangente de l'entrée\n expression numérique sous forme d'angle, exprimée en radians.\n\n ````\n ROW a=.12.9\n | EVAL atan=ATAN(a)\n ````\n ", + "languageDocumentation.documentationESQL.atan.markdown": " ### ATAN Renvoie l'arc tangente de l'expression numérique sous forme d'angle, exprimé en radians. ``` ROW a=12.9 | EVAL atan=ATAN(a) ```", "languageDocumentation.documentationESQL.atan2": "ATAN2", - "languageDocumentation.documentationESQL.atan2.markdown": "\n\n ### ATAN2\n L'angle entre l'axe positif des x et le rayon allant de\n l'origine au point (x , y) dans le plan cartésien, exprimée en radians.\n\n ````\n ROW y=12.9, x=.6\n | EVAL atan2=ATAN2(y, x)\n ````\n ", + "languageDocumentation.documentationESQL.atan2.markdown": " ### ATAN2 L'angle entre l'axe positif des x et le rayon allant de l'origine au point (x , y) dans le plan cartésien, exprimé en radians. ``` ROW y=12.9, x=.6 | EVAL atan2=ATAN2(y, x) ```", "languageDocumentation.documentationESQL.autoBucketFunction": "COMPARTIMENT", - "languageDocumentation.documentationESQL.autoBucketFunction.markdown": "### COMPARTIMENT\nCréer des groupes de valeurs, des compartiments (\"buckets\"), à partir d'une entrée d'un numéro ou d'un horodatage. La taille des compartiments peut être fournie directement ou choisie selon une plage de valeurs et de décompte recommandée.\n\n`BUCKET` a deux modes de fonctionnement : \n\n1. Dans lequel la taille du compartiment est calculée selon la recommandation de décompte d'un compartiment (quatre paramètres) et une plage.\n2. Dans lequel la taille du compartiment est fournie directement (deux paramètres).\n\nAvec un nombre cible de compartiments, le début d'une plage et la fin d'une plage, `BUCKET` choisit une taille de compartiment appropriée afin de générer le nombre cible de compartiments ou moins.\n\nPar exemple, demander jusqu'à 20 compartiments pour une année organisera les données en intervalles mensuels :\n\n````\nFROM employees\n| WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\"\n| STATS hire_date = MV_SORT(VALUES(hire_date)) BY month = BUCKET(hire_date, 20, \"1985-01-01T00:00:00Z\", \"1986-01-01T00:00:00Z\")\n| SORT hire_date\n````\n\n**REMARQUE** : Le but n'est pas de fournir le nombre précis de compartiments, mais plutôt de sélectionner une plage qui fournit, tout au plus, le nombre cible de compartiments.\n\nVous pouvez combiner `BUCKET` avec une agrégation pour créer un histogramme :\n\n````\nFROM employees\n| WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\"\n| STATS hires_per_month = COUNT(*) BY month = BUCKET(hire_date, 20, \"1985-01-01T00:00:00Z\", \"1986-01-01T00:00:00Z\")\n| SORT month\n````\n\n**REMARQUE** : `BUCKET` ne crée pas de compartiments qui ne correspondent à aucun document. C'est pourquoi, dans l'exemple précédent, il manque 1985-03-01 ainsi que d'autres dates.\n\nDemander d'autres compartiments peut résulter en une plage réduite. Par exemple, demander jusqu'à 100 compartiments en un an résulte en des compartiments hebdomadaires :\n\n````\nFROM employees\n| WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\"\n| STATS hires_per_week = COUNT(*) BY week = BUCKET(hire_date, 100, \"1985-01-01T00:00:00Z\", \"1986-01-01T00:00:00Z\")\n| SORT week\n````\n\n**REMARQUE** : `AUTO_BUCKET` ne filtre aucune ligne. Il n'utilise que la plage fournie pour choisir une taille de compartiment appropriée. Pour les lignes dont la valeur se situe en dehors de la plage, il renvoie une valeur de compartiment qui correspond à un compartiment situé en dehors de la plage. Associez `BUCKET` à `WHERE` pour filtrer les lignes.\n\nSi la taille de compartiment désirée est connue à l'avance, fournissez-la comme second argument, en ignorant la plage :\n\n````\nFROM employees\n| WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\"\n| STATS hires_per_week = COUNT(*) BY week = BUCKET(hire_date, 1 week)\n| SORT week\n````\n\n**REMARQUE** : Lorsque vous fournissez la taille du compartiment comme second argument, ce dernier doit être une période temporelle ou une durée.\n\n`BUCKET` peut également être utilisé pour des champs numériques. Par exemple, pour créer un histogramme de salaire :\n\n````\nFROM employees\n| STATS COUNT(*) by bs = BUCKET(salary, 20, 25324, 74999)\n| SORT bs\n````\n\nContrairement à l'exemple précédent qui filtre intentionnellement sur une plage temporelle, vous n'avez pas souvent besoin de filtrer sur une plage numérique. Vous devez trouver les valeurs min et max séparément. ES|QL n'a pas encore de façon aisée d'effectuer cette opération automatiquement.\n\nLa plage peut être ignorée si la taille désirée de compartiment est connue à l'avance. Fournissez-la simplement comme second argument :\n\n````\nFROM employees\n| WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\"\n| STATS c = COUNT(1) BY b = BUCKET(salary, 5000.)\n| SORT b\n````\n\n**REMARQUE** : Lorsque vous fournissez la taille du compartiment comme second argument, elle doit être de type à **virgule flottante**.\n\nVoici un exemple sur comment créer des compartiments horaires pour les dernières 24 heures, et calculer le nombre d'événements par heure :\n\n````\nFROM sample_data\n| WHERE @timestamp >= NOW() - 1 day and @timestamp < NOW()\n| STATS COUNT(*) BY bucket = BUCKET(@timestamp, 25, NOW() - 1 day, NOW())\n````\n\nVoici un exemple permettant de créer des compartiments mensuels pour l'année 1985, et calculer le salaire moyen par mois d'embauche :\n\n````\nFROM employees\n| WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\"\n| STATS AVG(salary) BY bucket = BUCKET(hire_date, 20, \"1985-01-01T00:00:00Z\", \"1986-01-01T00:00:00Z\")\n| SORT bucket\n````\n\n`BUCKET` peut être utilisé pour les parties de groupage et d'agrégation de la commande `STATS …​ BY ...`, tant que la partie d'agrégation de la fonction est **référencée par un alias défini dans la partie de groupage**, ou que celle-ci est invoquée avec exactement la même expression.\n\nPar exemple :\n\n````\nFROM employees\n| STATS s1 = b1 + 1, s2 = BUCKET(salary / 1000 + 999, 50.) + 2 BY b1 = BUCKET(salary / 100 + 99, 50.), b2 = BUCKET(salary / 1000 + 999, 50.)\n| SORT b1, b2\n| KEEP s1, b1, s2, b2\n````\n ", + "languageDocumentation.documentationESQL.autoBucketFunction.markdown": "### BUCKET Crée des groupes de valeurs et des compartiments (\"buckets\"), à partir d'une entrée numérique ou d'un horodatage. La taille des compartiments peut être fournie directement ou choisie selon une plage de valeurs et de décompte recommandée. `BUCKET` a deux modes de fonctionnement : 1. Dans lequel la taille du compartiment est calculée selon la recommandation de décompte d'un compartiment (quatre paramètres) et une plage. 2. Dans lequel la taille du compartiment est fournie directement (deux paramètres). Avec un nombre cible de compartiments, le début d'une plage et la fin d'une plage, `BUCKET` choisit une taille de compartiment appropriée afin de générer le nombre cible de compartiments ou moins. Par exemple, demander jusqu'à 20 compartiments pour une année organisera les données en intervalles mensuels : ``` FROM employees | WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\" | STATS hire_date = MV_SORT(VALUES(hire_date)) BY month = BUCKET(hire_date, 20, \"1985-01-01T00:00:00Z\", \"1986-01-01T00:00:00Z\") | SORT hire_date ``` **REMARQUE** : Le but n'est pas de fournir le nombre précis de compartiments, mais plutôt de sélectionner une plage qui fournit, tout au plus, le nombre cible de compartiments. Vous pouvez combiner `BUCKET` avec une agrégation pour créer un histogramme : ``` FROM employees | WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\" | STATS hires_per_month = COUNT(*) BY month = BUCKET(hire_date, 20, \"1985-01-01T00:00:00Z\", \"1986-01-01T00:00:00Z\") | SORT month ``` **REMARQUE** : `BUCKET` ne crée pas de compartiments qui ne correspondent à aucun document. C'est pourquoi, dans l'exemple précédent, il manque 1985-03-01 ainsi que d'autres dates. Demander d'autres compartiments peut résulter en une plage réduite. Par exemple, demander jusqu'à 100 compartiments en un an résulte en des compartiments hebdomadaires : ``` FROM employees | WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\" | STATS hires_per_week = COUNT(*) BY week = BUCKET(hire_date, 100, \"1985-01-01T00:00:00Z\", \"1986-01-01T00:00:00Z\") | SORT week ``` **REMARQUE** : `BUCKET` ne filtre aucune ligne. Il n'utilise que la plage fournie pour choisir une taille de compartiment appropriée. Pour les lignes dont la valeur se situe en dehors de la plage, il renvoie une valeur de compartiment qui correspond à un compartiment situé en dehors de la plage. Associez `BUCKET` à `WHERE` pour filtrer les lignes. Si la taille de compartiment désirée est connue à l'avance, fournissez-la comme second argument, en ignorant la plage : ``` FROM employees | WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\" | STATS hires_per_week = COUNT(*) BY week = BUCKET(hire_date, 1 week) | SORT week ``` **REMARQUE** : Lorsque vous fournissez la taille du compartiment comme second argument, ce dernier doit être une période temporelle ou une durée. `BUCKET` peut également être utilisé pour des champs numériques. Par exemple, pour créer un histogramme de salaire : ``` FROM employees | STATS COUNT(*) by bs = BUCKET(salary, 20, 25324, 74999) | SORT bs ``` Contrairement à l'exemple précédent qui filtre intentionnellement sur une plage temporelle, vous n'avez pas souvent besoin de filtrer sur une plage numérique. Vous devez trouver les valeurs min et max séparément. ES|QL n'a pas encore de façon aisée d'effectuer cette opération automatiquement. La plage peut être ignorée si la taille désirée de compartiment est connue à l'avance. Fournissez-la simplement comme second argument : ``` FROM employees | WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\" | STATS c = COUNT(1) BY b = BUCKET(salary, 5000.) | SORT b ``` **REMARQUE** : Lorsque vous fournissez la taille du compartiment comme second argument, elle doit être de type à **virgule flottante**. Voici un exemple sur comment créer des compartiments horaires pour les dernières 24 heures, et calculer le nombre d'événements par heure : ``` FROM sample_data | WHERE @timestamp >= NOW() - 1 day and @timestamp < NOW() | STATS COUNT(*) BY bucket = BUCKET(@timestamp, 25, NOW() - 1 day, NOW()) ``` Voici un exemple sur comment créer des compartiments mensuels pour l'année 1985, et calculer le salaire moyen par mois d'embauche : ``` FROM employees | WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\" | STATS AVG(salary) BY bucket = BUCKET(hire_date, 20, \"1985-01-01T00:00:00Z\", \"1986-01-01T00:00:00Z\") | SORT bucket ``` `BUCKET` peut être utilisé à la fois dans la partie agrégation et dans la partie regroupement de la commande `STATS ... BY ...`, tant que la partie d'agrégation de la fonction est **référencée par un alias défini dans la partie de groupage**, ou que celle-ci est invoquée avec exactement la même expression. Par exemple : ``` FROM employees | STATS s1 = b1 + 1, s2 = BUCKET(salary / 1000 + 999, 50.) + 2 BY b1 = BUCKET(salary / 100 + 99, 50.), b2 = BUCKET(salary / 1000 + 999, 50.) | SORT b1, b2 | KEEP s1, b1, s2, b2 ```", + "languageDocumentation.documentationESQL.avg": "AVG", + "languageDocumentation.documentationESQL.avg.markdown": " ### AVG La moyenne d'un champ numérique. ``` FROM employees | STATS AVG(height) ```", "languageDocumentation.documentationESQL.binaryOperators": "Opérateurs binaires", - "languageDocumentation.documentationESQL.binaryOperators.markdown": "### Opérateurs binaires\nLes opérateurs de comparaison binaire suivants sont pris en charge :\n\n* égalité : `==`\n* inégalité : `!=`\n* inférieur à : `<`\n* inférieur ou égal à : `<=`\n* supérieur à : `>`\n* supérieur ou égal à : `>=`\n* ajouter : `+`\n* soustraire : `-`\n* multiplier par : `*`\n* diviser par : `/`\n* module : `%`\n ", + "languageDocumentation.documentationESQL.binaryOperators.markdown": "### Opérateurs binaires Les opérateurs de comparaison binaires suivants sont pris en charge : * égalité : `==` * inégalité : `!=` * inférieur à : `<` * inférieur ou égal à : `<=` * supérieur à : `>` * supérieur ou égal à : `>=` * ajouter : `+` * soustraire : `-` * multiplier : `*` * diviser par : `/` * modulo : `%`", "languageDocumentation.documentationESQL.booleanOperators": "Opérateurs booléens", - "languageDocumentation.documentationESQL.booleanOperators.markdown": "### Opérateurs booléens\nLes opérateurs booléens suivants sont pris en charge :\n\n* `AND`\n* `OR`\n* `NOT`\n ", + "languageDocumentation.documentationESQL.booleanOperators.markdown": "### Opérateurs booléens Les opérateurs booléens suivants sont pris en charge : * `AND` * `OR` * `NOT`", "languageDocumentation.documentationESQL.bucket": "COMPARTIMENT", - "languageDocumentation.documentationESQL.bucket.markdown": "\n\n ### COMPARTIMENT\n Créer des groupes de valeurs, des compartiments (\"buckets\"), à partir d'une entrée d'un numéro ou d'un horodatage.\n La taille des compartiments peut être fournie directement ou choisie selon une plage de valeurs et de décompte recommandée.\n\n ````\n FROM employees\n | WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\"\n | STATS hire_date = MV_SORT(VALUES(hire_date)) BY month = BUCKET(hire_date, 20, \"1985-01-01T00:00:00Z\", \"1986-01-01T00:00:00Z\")\n | SORT hire_date\n ````\n ", + "languageDocumentation.documentationESQL.bucket.markdown": " ### BUCKET Crée des groupes de valeurs et des compartiments (\"buckets\"), à partir d'une entrée numérique ou d'un horodatage. La taille des compartiments peut être fournie directement ou choisie selon une plage de valeurs et de décompte recommandée. ``` FROM employees | WHERE hire_date >= \"1985-01-01T00:00:00Z\" AND hire_date < \"1986-01-01T00:00:00Z\" | STATS hire_date = MV_SORT(VALUES(hire_date)) BY month = BUCKET(hire_date, 20, \"1985-01-01T00:00:00Z\", \"1986-01-01T00:00:00Z\") | SORT hire_date ```", "languageDocumentation.documentationESQL.case": "CASE", - "languageDocumentation.documentationESQL.case.markdown": "\n\n ### CAS\n Accepte les paires de conditions et de valeurs. La fonction renvoie la valeur qui\n appartient à la première condition étant évaluée comme `true`.\n\n Si le nombre d'arguments est impair, le dernier argument est la valeur par défaut qui est\n renvoyée si aucune condition ne correspond. Si le nombre d'arguments est pair, et\n qu'aucune condition ne correspond, la fonction renvoie `null`.\n\n ````\n FROM employees\n | EVAL type = CASE(\n languages <= 1, \"monolingual\",\n languages <= 2, \"bilingual\",\n \"polyglot\")\n | KEEP emp_no, languages, type\n ````\n ", + "languageDocumentation.documentationESQL.case.markdown": " ### CASE Accepte les paires de conditions et de valeurs. La fonction renvoie la valeur correspondant à la première condition évaluée à `true` (vraie). Si le nombre d'arguments est impair, le dernier argument est la valeur par défaut qui est renvoyée si aucune condition ne correspond. Si le nombre d'arguments est pair, et qu'aucune condition ne correspond, la fonction renvoie `null`. ``` FROM employees | EVAL type = CASE( languages <= 1, \"monolingual\", languages <= 2, \"bilingual\", \"polyglot\") | KEEP emp_no, languages, type ```", "languageDocumentation.documentationESQL.castOperator": "Cast (::)", - "languageDocumentation.documentationESQL.castOperator.markdown": "### CAST (`::`)\nL'opérateur `::` fournit une syntaxe alternative pratique au type de converstion de fonction `TO_`.\n\nExemple :\n````\nROW ver = CONCAT((\"0\"::INT + 1)::STRING, \".2.3\")::VERSION\n````\n ", + "languageDocumentation.documentationESQL.castOperator.markdown": "### CAST (`::`) L'opérateur `::` fournit une autre syntaxe pratique pour les fonctions de conversion de type `TO_`. Exemple : ``` ROW ver = CONCAT((\"0\"::INT + 1)::STRING, \".2.3\")::VERSION ```", "languageDocumentation.documentationESQL.cbrt": "CBRT", - "languageDocumentation.documentationESQL.cbrt.markdown": "\n\n ### CBRT\n Renvoie la racine cubique d'un nombre. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée.\n La racine cubique de l’infini est nulle.\n\n ````\n ROW d = 1000.0\n | EVAL c = cbrt(d)\n ````\n ", + "languageDocumentation.documentationESQL.cbrt.markdown": " ### CBRT Renvoie la racine cubique d'un nombre. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée. La racine cubique de l'infini est nulle. ``` ROW d = 1000.0 | EVAL c = cbrt(d) ```", "languageDocumentation.documentationESQL.ceil": "CEIL", - "languageDocumentation.documentationESQL.ceil.markdown": "\n\n ### CEIL\n Arrondir un nombre à l'entier supérieur.\n\n ```\n ROW a=1.8\n | EVAL a=CEIL(a)\n ```\n Remarque : Il s'agit d'un noop pour `long` (y compris non signé) et `integer`. Pour `double`, la fonction choisit la valeur `double` la plus proche de l'entier, de manière similaire à la méthode Math.ceil.\n ", + "languageDocumentation.documentationESQL.ceil.markdown": " ### CEIL Arrondit un nombre à l'entier supérieur. ``` ROW a=1.8 | EVAL a=CEIL(a) ``` Remarque : Il s'agit d'un noop pour `long` (y compris non signé) et `integer`. Pour `double`, la fonction choisit la valeur `double` la plus proche de l'entier, de manière similaire à la méthode Math.ceil.", "languageDocumentation.documentationESQL.cidr_match": "CIDR_MATCH", - "languageDocumentation.documentationESQL.cidr_match.markdown": "\n\n ### CIDR_MATCH\n Renvoie `true` si l'IP fournie est contenue dans l'un des blocs CIDR fournis.\n\n ````\n FROM hosts \n | WHERE CIDR_MATCH(ip1, \"127.0.0.2/32\", \"127.0.0.3/32\") \n | KEEP card, host, ip0, ip1\n ````\n ", + "languageDocumentation.documentationESQL.cidr_match.markdown": " ### CIDR_MATCH Renvoie `true` si l'IP fournie est contenue dans l'un des blocs CIDR fournis. ``` FROM hosts | WHERE CIDR_MATCH(ip1, \"127.0.0.2/32\", \"127.0.0.3/32\") | KEEP card, host, ip0, ip1 ```", "languageDocumentation.documentationESQL.coalesce": "COALESCE", - "languageDocumentation.documentationESQL.coalesce.markdown": "\n\n ### COALESCE\n Renvoie le premier de ses arguments qui n'est pas nul. Si tous les arguments sont nuls, `null` est renvoyé.\n\n ````\n ROW a=null, b=\"b\"\n | EVAL COALESCE(a, b)\n ````\n ", + "languageDocumentation.documentationESQL.coalesce.markdown": " ### COALESCE Renvoie le premier de ses arguments qui n'est pas nul. Si tous les arguments sont nuls, `null` est renvoyé. ``` ROW a=null, b=\"b\" | EVAL COALESCE(a, b) ```", "languageDocumentation.documentationESQL.commandsDescription": "Une commande source produit un tableau, habituellement avec des données issues d'Elasticsearch. ES|QL est compatible avec les commandes sources suivantes.", "languageDocumentation.documentationESQL.concat": "CONCAT", - "languageDocumentation.documentationESQL.concat.markdown": "\n\n ### CONCAT\n Concatène deux ou plusieurs chaînes.\n\n ```\n FROM employees\n | KEEP first_name, last_name\n | EVAL fullname = CONCAT(first_name, \" \", last_name)\n ````\n ", + "languageDocumentation.documentationESQL.concat.markdown": " ### CONCAT Concatène deux ou plusieurs chaînes. ``` FROM employees | KEEP first_name, last_name | EVAL fullname = CONCAT(first_name, \" \", last_name) ```", "languageDocumentation.documentationESQL.cos": "COS", - "languageDocumentation.documentationESQL.cos.markdown": "\n\n ### COS\n Renvoie le cosinus d'un angle.\n\n ````\n ROW a=1.8 \n | EVAL cos=COS(a)\n ````\n ", + "languageDocumentation.documentationESQL.cos.markdown": " ### COS Renvoie le cosinus d'un angle. ``` ROW a=1.8 | EVAL cos=COS(a) ```", "languageDocumentation.documentationESQL.cosh": "COSH", - "languageDocumentation.documentationESQL.cosh.markdown": "\n\n ### COSH\n Renvoie le cosinus hyperbolique d'un angle.\n\n ````\n ROW a=1.8 \n | EVAL cosh=COSH(a)\n ```\n ", + "languageDocumentation.documentationESQL.cosh.markdown": " ### COSH Renvoie le cosinus hyperbolique d'un nombre. ``` ROW a=1.8 | EVAL cosh=COSH(a) ```", + "languageDocumentation.documentationESQL.count": "COUNT", + "languageDocumentation.documentationESQL.count_distinct": "COUNT_DISTINCT", + "languageDocumentation.documentationESQL.count_distinct.markdown": " ### COUNT_DISTINCT Renvoie le nombre approximatif de valeurs distinctes. ``` FROM hosts | STATS COUNT_DISTINCT(ip0), COUNT_DISTINCT(ip1) ```", + "languageDocumentation.documentationESQL.count.markdown": " ### COUNT Renvoie le nombre total de valeurs en entrée. ``` FROM employees | STATS COUNT(height) ```", "languageDocumentation.documentationESQL.date_diff": "DATE_DIFF", - "languageDocumentation.documentationESQL.date_diff.markdown": "\n\n ### DATE_DIFF\n Soustrait le `startTimestamp` du `endTimestamp` et renvoie la différence en multiples `d'unité`.\n Si `startTimestamp` est postérieur à `endTimestamp`, des valeurs négatives sont renvoyées.\n\n ````\n ROW date1 = TO_DATETIME(\"2023-12-02T11:00:00.000Z\"), date2 = TO_DATETIME(\"2023-12-02T11:00:00.001Z\")\n | EVAL dd_ms = DATE_DIFF(\"microseconds\", date1, date2)\n ````\n ", + "languageDocumentation.documentationESQL.date_diff.markdown": " ### DATE_DIFF Soustrait le `startTimestamp` du `endTimestamp` et renvoie la différence en multiples d'unité (`unit`). Si `startTimestamp` est postérieur à `endTimestamp`, des valeurs négatives sont renvoyées. ``` ROW date1 = TO_DATETIME(\"2023-12-02T11:00:00.000Z\"), date2 = TO_DATETIME(\"2023-12-02T11:00:00.001Z\") | EVAL dd_ms = DATE_DIFF(\"microseconds\", date1, date2) ```", "languageDocumentation.documentationESQL.date_extract": "DATE_EXTRACT", - "languageDocumentation.documentationESQL.date_extract.markdown": "\n\n ### DATE_EXTRACT\n Extrait des parties d'une date, telles que l'année, le mois, le jour, l'heure.\n\n ````\n ROW date = DATE_PARSE(\"yyyy-MM-dd\", \"2022-05-06\")\n | EVAL year = DATE_EXTRACT(\"year\", date)\n ````\n ", + "languageDocumentation.documentationESQL.date_extract.markdown": " ### DATE_EXTRACT Extrait des parties d'une date, telles que l'année, le mois, le jour, l'heure. ``` ROW date = DATE_PARSE(\"yyyy-MM-dd\", \"2022-05-06\") | EVAL year = DATE_EXTRACT(\"year\", date) ```", "languageDocumentation.documentationESQL.date_format": "DATE_FORMAT", - "languageDocumentation.documentationESQL.date_format.markdown": "\n\n ### DATE_FORMAT\n Renvoie une représentation sous forme de chaîne d'une date dans le format fourni.\n\n ````\n FROM employees\n | KEEP first_name, last_name, hire_date\n | EVAL hired = DATE_FORMAT(\"YYYY-MM-dd\", hire_date)\n ````\n ", + "languageDocumentation.documentationESQL.date_format.markdown": " ### DATE_FORMAT Renvoie une représentation sous forme de chaîne d'une date dans le format fourni. ``` FROM employees | KEEP first_name, last_name, hire_date | EVAL hired = DATE_FORMAT(\"yyyy-MM-dd\", hire_date) ```", "languageDocumentation.documentationESQL.date_parse": "DATE_PARSE", - "languageDocumentation.documentationESQL.date_parse.markdown": "\n\n ### DATE_PARSE\n Renvoie une date en analysant le deuxième argument selon le format spécifié dans le premier argument.\n\n ````\n ROW date_string = \"2022-05-06\"\n | EVAL date = DATE_PARSE(\"yyyy-MM-dd\", date_string)\n ````\n ", + "languageDocumentation.documentationESQL.date_parse.markdown": " ### DATE_PARSE Renvoie une date en analysant le deuxième argument selon le format spécifié dans le premier argument. ``` ROW date_string = \"2022-05-06\" | EVAL date = DATE_PARSE(\"yyyy-MM-dd\", date_string) ```", "languageDocumentation.documentationESQL.date_trunc": "DATE_TRUNC", - "languageDocumentation.documentationESQL.date_trunc.markdown": "\n\n ### DATE_TRUNC\n Arrondit une date à l'intervalle le plus proche.\n\n ```\n FROM employees\n | KEEP first_name, last_name, hire_date\n | EVAL year_hired = DATE_TRUNC(1 year, hire_date)\n ````\n ", + "languageDocumentation.documentationESQL.date_trunc.markdown": " ### DATE_TRUNC Arrondit une date à l'intervalle le plus proche. ``` FROM employees | KEEP first_name, last_name, hire_date | EVAL year_hired = DATE_TRUNC(1 year, hire_date) ```", "languageDocumentation.documentationESQL.dissect": "DISSECT", - "languageDocumentation.documentationESQL.dissect.markdown": "### DISSECT\n`DISSECT` vous permet d'extraire des données structurées d'une chaîne. `DISSECT` compare la chaîne à un modèle basé sur les délimiteurs, et extrait les clés indiquées en tant que colonnes.\n\nPour obtenir la syntaxe des modèles \"dissect\", consultez [la documentation relative au processeur \"dissect\"](https://www.elastic.co/guide/en/elasticsearch/reference/current/dissect-processor.html).\n\n```\nROW a = \"1953-01-23T12:15:00Z - some text - 127.0.0.1\"\n| DISSECT a \"%'{Y}-%{M}-%{D}T%{h}:%{m}:%{s}Z - %{msg} - %{ip}'\"\n```` ", + "languageDocumentation.documentationESQL.dissect.markdown": "### DISSECT `DISSECT` vous permet d'extraire des données structurées d'une chaîne. `DISSECT` compare la chaîne à un modèle basé sur les délimiteurs, et extrait les clés indiquées en tant que colonnes. Pour obtenir la syntaxe des modèles \"dissect\", consultez la [documentation relative au processeur \"dissect\"](https://www.elastic.co/guide/en/elasticsearch/reference/current/dissect-processor.html). ``` ROW a = \"1953-01-23T12:15:00Z - some text - 127.0.0.1\" | DISSECT a \"%'{Y}-%{M}-%{D}T%{h}:%{m}:%{s}Z - %{msg} - %{ip}'\" ```", "languageDocumentation.documentationESQL.drop": "DROP", - "languageDocumentation.documentationESQL.drop.markdown": "### DROP\nAfin de supprimer certaines colonnes d'un tableau, utilisez `DROP` :\n \n```\nFROM employees\n| DROP height\n```\n\nPlutôt que de spécifier chaque colonne par son nom, vous pouvez utiliser des caractères génériques pour supprimer toutes les colonnes dont le nom correspond à un modèle :\n\n```\nFROM employees\n| DROP height*\n````\n ", + "languageDocumentation.documentationESQL.drop.markdown": "### DROP Afin de supprimer certaines colonnes d'un tableau, utilisez `DROP` : ``` FROM employees | DROP height ``` Plutôt que de spécifier chaque colonne par son nom, vous pouvez utiliser des caractères génériques pour supprimer toutes les colonnes dont le nom correspond à un modèle : ``` FROM employees | DROP height* ```", "languageDocumentation.documentationESQL.e": "E", - "languageDocumentation.documentationESQL.e.markdown": "\n\n ### E\n Retourne le nombre d'Euler.\n\n ````\n ROW E()\n ````\n ", + "languageDocumentation.documentationESQL.e.markdown": " ### E Renvoie le nombre d'Euler. ``` ROW E() ```", "languageDocumentation.documentationESQL.ends_with": "ENDS_WITH", - "languageDocumentation.documentationESQL.ends_with.markdown": "\n\n ### ENDS_WITH\n Renvoie une valeur booléenne qui indique si une chaîne de mots-clés se termine par une autre chaîne.\n\n ````\n FROM employees\n | KEEP last_name\n | EVAL ln_E = ENDS_WITH(last_name, \"d\")\n ````\n ", + "languageDocumentation.documentationESQL.ends_with.markdown": " ### ENDS_WITH Renvoie une valeur booléenne qui indique si une chaîne de mots-clés se termine par une autre chaîne. ``` FROM employees | KEEP last_name | EVAL ln_E = ENDS_WITH(last_name, \"d\") ```", "languageDocumentation.documentationESQL.enrich": "ENRICH", - "languageDocumentation.documentationESQL.enrich.markdown": "### ENRICH\nVous pouvez utiliser `ENRICH` pour ajouter les données de vos index existants aux enregistrements entrants. Une fonction similaire à l'[enrichissement par ingestion](https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest-enriching-data.html), mais qui fonctionne au moment de la requête.\n\n```\nROW language_code = \"1\"\n| ENRICH languages_policy\n```\n\n`ENRICH` requiert l'exécution d'une [politique d'enrichissement](https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest-enriching-data.html#enrich-policy). La politique d'enrichissement définit un champ de correspondance (un champ clé) et un ensemble de champs d'enrichissement.\n\n`ENRICH` recherche les enregistrements dans l'[index d'enrichissement](https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest-enriching-data.html#enrich-index) en se basant sur la valeur du champ de correspondance. La clé de correspondance dans l'ensemble de données d'entrée peut être définie en utilisant `ON `. Si elle n'est pas spécifiée, la correspondance sera effectuée sur un champ portant le même nom que le champ de correspondance défini dans la politique d'enrichissement.\n\n```\nROW a = \"1\"\n| ENRICH languages_policy ON a\n```\n\nVous pouvez indiquer quels attributs (parmi ceux définis comme champs d'enrichissement dans la politique) doivent être ajoutés au résultat, en utilisant la syntaxe `WITH , ...`.\n\n```\nROW a = \"1\"\n| ENRICH languages_policy ON a WITH language_name\n```\n\nLes attributs peuvent également être renommés à l'aide de la syntaxe `WITH new_name=`\n\n```\nROW a = \"1\"\n| ENRICH languages_policy ON a WITH name = language_name\n````\n\nPar défaut (si aucun `WITH` n'est défini), `ENRICH` ajoute au résultat tous les champs d'enrichissement définis dans la politique d'enrichissement.\n\nEn cas de collision de noms, les champs nouvellement créés remplacent les champs existants.\n ", + "languageDocumentation.documentationESQL.enrich.markdown": "### ENRICH Vous pouvez utiliser `ENRICH` pour ajouter les données de vos index existants aux enregistrements entrants. Cette fonction est similaire à [\"ingest enrich\"](https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest-enriching-data.html), mais agit au moment de la requête. ``` ROW language_code = \"1\" | ENRICH languages_policy ``` `ENRICH` nécessite l'exécution d'une [politique d'enrichissement](https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest-enriching-data.html#enrich-policy). La politique d'enrichissement définit un champ de correspondance (un champ clé) et un ensemble de champs d'enrichissement. `ENRICH` recherchera les enregistrements dans l'[index d'enrichissement](https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest-enriching-data.html#enrich-index) en se basant sur la valeur du champ de correspondance. La clé de correspondance dans l'ensemble de données d'entrée peut être définie en utilisant `ON `. Si elle n'est pas spécifiée, la correspondance sera effectuée sur un champ portant le même nom que le champ de correspondance défini dans la politique d'enrichissement. ``` ROW a = \"1\" | ENRICH languages_policy ON a ``` Vous pouvez indiquer quels attributs (parmi ceux définis comme champs d'enrichissement dans la politique) doivent être ajoutés au résultat, en utilisant la syntaxe `WITH , ...`. ``` ROW a = \"1\" | ENRICH languages_policy ON a WITH language_name ``` Les attributs peuvent également être renommés à l'aide de `WITH new_name=` ``` ROW a = \"1\" | ENRICH languages_policy ON a WITH name = language_name ``` Par défaut (si aucun `WITH` n'est défini), `ENRICH` ajoute au résultat tous les champs d'enrichissement définis dans la politique d'enrichissement. En cas de collision de noms, les champs nouvellement créés remplacent les champs existants.", "languageDocumentation.documentationESQL.eval": "EVAL", - "languageDocumentation.documentationESQL.eval.markdown": "### EVAL\n`EVAL` permet d'ajouter des colonnes :\n\n````\nFROM employees\n| KEEP first_name, last_name, height\n| EVAL height_feet = height * 3.281, height_cm = height * 100\n````\n\nSi la colonne indiquée existe déjà, la colonne existante sera supprimée et la nouvelle colonne sera ajoutée au tableau :\n\n````\nFROM employees\n| KEEP first_name, last_name, height\n| EVAL height = height * 3.281\n````\n\n#### Fonctions\n`EVAL` prend en charge diverses fonctions de calcul des valeurs. Pour en savoir plus, consultez les fonctions.\n ", + "languageDocumentation.documentationESQL.eval.markdown": "### EVAL `EVAL` permet d'ajouter des colonnes : ``` FROM employees | KEEP first_name, last_name, height | EVAL height_feet = height * 3.281, height_cm = height * 100 ``` Si la colonne indiquée existe déjà, la colonne existante sera supprimée et la nouvelle colonne sera ajoutée au tableau : ``` FROM employees | KEEP first_name, last_name, height | EVAL height = height * 3.281 ``` #### Fonctions `EVAL` prend en charge diverses fonctions de calcul des valeurs. Pour en savoir plus, consultez les fonctions.", + "languageDocumentation.documentationESQL.exp": "EXP", + "languageDocumentation.documentationESQL.exp.markdown": " ### EXP Renvoie la valeur de \"e\" élevée à la puissance d'un nombre donné. ``` ROW d = 5.0 | EVAL s = EXP(d) ```", "languageDocumentation.documentationESQL.floor": "FLOOR", - "languageDocumentation.documentationESQL.floor.markdown": "\n\n ### FLOOR\n Arrondir un nombre à l'entier inférieur.\n\n ````\n ROW a=1.8\n | EVAL a=FLOOR(a)\n ````\n Remarque : Il s'agit d'un noop pour `long` (y compris non signé) et `integer`.\n Pour `double`, la fonction choisit la valeur `double` la plus proche de l'entier,\n de manière similaire à Math.floor.\n ", + "languageDocumentation.documentationESQL.floor.markdown": " ### FLOOR Arrondit un nombre à l'entier inférieur. ``` ROW a=1.8 | EVAL a=FLOOR(a) ``` Remarque : Il s'agit d'un noop pour `long` (y compris non signé) et `integer`. Pour `double`, la fonction choisit la valeur `double` la plus proche de l'entier, de manière similaire à la méthode Math.floor.", "languageDocumentation.documentationESQL.from": "FROM", "languageDocumentation.documentationESQL.from_base64": "FROM_BASE64", - "languageDocumentation.documentationESQL.from_base64.markdown": "\n\n ### FROM_BASE64\n Décodez une chaîne base64.\n\n ````\n row a = \"ZWxhc3RpYw==\" \n | eval d = from_base64(a)\n ````\n ", - "languageDocumentation.documentationESQL.from.markdown": "### FROM\nLa commande source `FROM` renvoie un tableau contenant jusqu'à 10 000 documents issus d'un flux de données, d'un index ou d'un alias. Chaque ligne du tableau obtenu correspond à un document. Chaque colonne correspond à un champ et est accessible par le nom de ce champ.\n\n````\nFROM employees\n````\n\nVous pouvez utiliser des [calculs impliquant des dates](https://www.elastic.co/guide/en/elasticsearch/reference/current/api-conventions.html#api-date-math-index-names) pour désigner les indices, les alias et les flux de données. Cela peut s'avérer utile pour les données temporelles.\n\nUtilisez des listes séparées par des virgules ou des caractères génériques pour rechercher plusieurs flux de données, indices ou alias :\n\n````\nFROM employees-00001,employees-*\n````\n\n#### Métadonnées\n\nES|QL peut accéder aux champs de métadonnées suivants :\n\n* `_index` : l'index auquel appartient le document. Le champ est du type `keyword`.\n* `_id` : l'identifiant du document source. Le champ est du type `keyword`.\n* `_id` : la version du document source. Le champ est du type `long`.\n\nUtilisez la directive `METADATA` pour activer les champs de métadonnées :\n\n````\nFROM index [METADATA _index, _id]\n````\n\nLes champs de métadonnées ne sont disponibles que si la source des données est un index. Par conséquent, `FROM` est la seule commande source qui prend en charge la directive `METADATA`.\n\nUne fois activés, les champs sont disponibles pour les commandes de traitement suivantes, tout comme les autres champs de l'index :\n\n````\nFROM ul_logs, apps [METADATA _index, _version]\n| WHERE id IN (13, 14) AND _version == 1\n| EVAL key = CONCAT(_index, \"_\", TO_STR(id))\n| SORT id, _index\n| KEEP id, _index, _version, key\n````\n\nDe même, comme pour les champs d'index, une fois l'agrégation effectuée, un champ de métadonnées ne sera plus accessible aux commandes suivantes, sauf s'il est utilisé comme champ de regroupement :\n\n````\nFROM employees [METADATA _index, _id]\n| STATS max = MAX(emp_no) BY _index\n````\n ", + "languageDocumentation.documentationESQL.from_base64.markdown": " ### FROM_BASE64 Décode une chaîne base64. ``` row a = \"ZWxhc3RpYw==\" | eval d = from_base64(a) ```", + "languageDocumentation.documentationESQL.from.markdown": "### FROM La commande source `FROM` renvoie un tableau contenant jusqu'à 10 000 documents issus d'un flux de données, d'un index ou d'un alias. Chaque ligne du tableau obtenu correspond à un document. Chaque colonne correspond à un champ et est accessible par le nom de ce champ. ``` FROM employees ``` Vous pouvez utiliser des [calculs impliquant des dates](https://www.elastic.co/guide/en/elasticsearch/reference/current/api-conventions.html#api-date-math-index-names) pour désigner les indices, les alias et les flux de données. Cela peut s'avérer utile pour les données temporelles. Utilisez des listes séparées par des virgules ou des caractères génériques pour rechercher plusieurs flux de données, indices ou alias : ``` FROM employees-00001,employees-* ``` #### Métadonnées ES|QL peut accéder aux champs de métadonnées suivants : * `_index` : l'index auquel appartient le document. Le champ est du type `keyword`. * `_id` : l'identifiant du document source. Le champ est du type `keyword`. * `_version` : la version du document source. Le champ est du type `long`. Utilisez la directive `METADATA` pour activer les champs de métadonnées : ``` FROM index [METADATA _index, _id] ``` Les champs de métadonnées ne sont disponibles que si la source des données est un index. Par conséquent, `FROM` est la seule commande source qui prend en charge la directive `METADATA`. Une fois activés, les champs sont disponibles pour les commandes de traitement suivantes, tout comme les autres champs de l'index : ``` FROM ul_logs, apps [METADATA _index, _version] | WHERE id IN (13, 14) AND _version == 1 | EVAL key = CONCAT(_index, \"_\", TO_STR(id)) | SORT id, _index | KEEP id, _index, _version, key ``` De même, comme pour les champs d'index, une fois l'agrégation effectuée, un champ de métadonnées ne sera plus accessible aux commandes suivantes, sauf s'il est utilisé comme champ de regroupement : ``` FROM employees [METADATA _index, _id] | STATS max = MAX(emp_no) BY _index ```", "languageDocumentation.documentationESQL.functions": "Fonctions", "languageDocumentation.documentationESQL.functionsDocumentationESQLDescription": "Les fonctions sont compatibles avec \"ROW\" (Ligne), \"EVAL\" (Évaluation) et \"WHERE\" (Où).", "languageDocumentation.documentationESQL.greatest": "GREATEST", - "languageDocumentation.documentationESQL.greatest.markdown": "\n\n ### GREATEST\n Renvoie la valeur maximale de plusieurs colonnes. Similaire à `MV_MAX`\n sauf que ceci est destiné à une exécution sur plusieurs colonnes à la fois.\n\n ````\n ROW a = 10, b = 20\n | EVAL g = GREATEST(a, b)\n ````\n Remarque : Lorsque cette fonction est exécutée sur les champs `keyword` ou `text`, elle renvoie la dernière chaîne dans l'ordre alphabétique. Lorsqu'elle est exécutée sur des colonnes `boolean`, elle renvoie `true` si l'une des valeurs l'est.\n ", + "languageDocumentation.documentationESQL.greatest.markdown": " ### GREATEST Renvoie la valeur maximale de plusieurs colonnes. Cette fonction est similaire à `MV_MAX`. Toutefois, elle est destinée à être exécutée sur plusieurs colonnes à la fois. ``` ROW a = 10, b = 20 | EVAL g = GREATEST(a, b) ``` Remarque : Lorsque cette fonction est exécutée sur les champs `keyword` ou `text`, elle renvoie la dernière chaîne dans l'ordre alphabétique. Lorsqu'elle est exécutée sur des colonnes `boolean`, elle renvoie `true` si l'une des valeurs l'est.", "languageDocumentation.documentationESQL.grok": "GROK", - "languageDocumentation.documentationESQL.grok.markdown": "### GROK\n`GROK` vous permet d'extraire des données structurées d'une chaîne. `GROK` compare la chaîne à des modèles, sur la base d’expressions régulières, et extrait les modèles indiqués en tant que colonnes.\n\nPour obtenir la syntaxe des modèles \"grok\", consultez [la documentation relative au processeur \"grok\"](https://www.elastic.co/guide/en/elasticsearch/reference/current/grok-processor.html).\n\n````\nROW a = \"12 15.5 15.6 true\"\n| GROK a \"%'{NUMBER:b:int}' %'{NUMBER:c:float}' %'{NUMBER:d:double}' %'{WORD:e:boolean}'\"\n````\n ", + "languageDocumentation.documentationESQL.grok.markdown": "### GROK `GROK` vous permet d'extraire des données structurées d'une chaîne. `GROK` compare la chaîne à des modèles, sur la base d'expressions régulières, et extrait les modèles indiqués en tant que colonnes. Pour obtenir la syntaxe des modèles \"grok\", consultez la [documentation relative au processeur \"grok\"](https://www.elastic.co/guide/en/elasticsearch/reference/current/grok-processor.html). ``` ROW a = \"12 15.5 15.6 true\" | GROK a \"%'{NUMBER:b:int}' %'{NUMBER:c:float}' %'{NUMBER:d:double}' %'{WORD:e:boolean}'\" ```", "languageDocumentation.documentationESQL.groupingFunctions": "Fonctions de groupage", "languageDocumentation.documentationESQL.groupingFunctionsDocumentationESQLDescription": "Ces fonctions de regroupement peuvent être utilisées avec `STATS...BY` :", + "languageDocumentation.documentationESQL.hypot": "HYPOT", + "languageDocumentation.documentationESQL.hypot.markdown": " ### HYPOT Renvoie l'hypoténuse de deux nombres. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée. Les hypoténuses des infinis sont nulles. ``` ROW a = 3.0, b = 4.0 | EVAL c = HYPOT(a, b) ```", "languageDocumentation.documentationESQL.inOperator": "IN", - "languageDocumentation.documentationESQL.inOperator.markdown": "### IN\nL'opérateur `IN` permet de tester si un champ ou une expression est égal à un élément d'une liste de littéraux, de champs ou d'expressions :\n\n````\nROW a = 1, b = 4, c = 3\n| WHERE c-a IN (3, b / 2, a)\n````\n ", + "languageDocumentation.documentationESQL.inOperator.markdown": "### IN L'opérateur `IN` permet de tester si un champ ou une expression sont égaux à un élément d'une liste de littéraux, de champs ou d'expressions : ``` ROW a = 1, b = 4, c = 3 | WHERE c-a IN (3, b / 2, a) ```", "languageDocumentation.documentationESQL.ip_prefix": "IP_PREFIX", - "languageDocumentation.documentationESQL.ip_prefix.markdown": "\n\n ### IP_PREFIX\n Tronque une adresse IP à une longueur de préfixe donnée.\n\n ````\n row ip4 = to_ip(\"1.2.3.4\"), ip6 = to_ip(\"fe80::cae2:65ff:fece:feb9\")\n | eval ip4_prefix = ip_prefix(ip4, 24, 0), ip6_prefix = ip_prefix(ip6, 0, 112);\n ````\n ", + "languageDocumentation.documentationESQL.ip_prefix.markdown": " ### IP_PREFIX Tronque une adresse IP à une longueur de préfixe donnée. ``` row ip4 = to_ip(\"1.2.3.4\"), ip6 = to_ip(\"fe80::cae2:65ff:fece:feb9\") | eval ip4_prefix = ip_prefix(ip4, 24, 0), ip6_prefix = ip_prefix(ip6, 0, 112); ```", "languageDocumentation.documentationESQL.keep": "KEEP", - "languageDocumentation.documentationESQL.keep.markdown": "### KEEP\nLa commande `KEEP` permet de définir les colonnes qui seront renvoyées et l'ordre dans lequel elles le seront.\n\nPour limiter les colonnes retournées, utilisez une liste de noms de colonnes séparés par des virgules. Les colonnes sont renvoyées dans l'ordre indiqué :\n \n````\nFROM employees\n| KEEP first_name, last_name, height\n````\n\nPlutôt que de spécifier chaque colonne par son nom, vous pouvez utiliser des caractères génériques pour renvoyer toutes les colonnes dont le nom correspond à un modèle :\n\n````\nFROM employees\n| KEEP h*\n````\n\nLe caractère générique de l'astérisque (\"*\") placé de manière isolée transpose l'ensemble des colonnes qui ne correspondent pas aux autres arguments. La requête suivante renverra en premier lieu toutes les colonnes dont le nom commence par un h, puis toutes les autres colonnes :\n\n````\nFROM employees\n| KEEP h*, *\n````\n ", + "languageDocumentation.documentationESQL.keep.markdown": "### KEEP La commande `KEEP` permet de définir les colonnes qui seront renvoyées et l'ordre dans lequel elles le seront. Pour limiter les colonnes retournées, utilisez une liste de noms de colonnes séparés par des virgules. Les colonnes sont renvoyées dans l'ordre indiqué : ``` FROM employees | KEEP first_name, last_name, height ``` Plutôt que de spécifier chaque colonne par son nom, vous pouvez utiliser des caractères génériques pour renvoyer toutes les colonnes dont le nom correspond à un modèle : ``` FROM employees | KEEP h* ``` Le caractère générique de l'astérisque (`*`) placé de manière isolée transpose l'ensemble des colonnes qui ne correspondent pas aux autres arguments. La requête suivante renverra en premier lieu toutes les colonnes dont le nom commence par un \"h\", puis toutes les autres colonnes : ``` FROM employees | KEEP h*, * ```", "languageDocumentation.documentationESQL.least": "LEAST", - "languageDocumentation.documentationESQL.least.markdown": "\n\n ### LEAST\n Renvoie la valeur minimale de plusieurs colonnes. Cette fonction est similaire à `MV_MIN`. Toutefois, elle est destinée à être exécutée sur plusieurs colonnes à la fois.\n\n ````\n ROW a = 10, b = 20\n | EVAL l = LEAST(a, b)\n ````\n ", + "languageDocumentation.documentationESQL.least.markdown": " ### LEAST Renvoie la valeur minimale de plusieurs colonnes. Cette fonction est similaire à `MV_MIN`. Toutefois, elle est destinée à être exécutée sur plusieurs colonnes à la fois. ``` ROW a = 10, b = 20 | EVAL l = LEAST(a, b) ```", "languageDocumentation.documentationESQL.left": "LEFT", - "languageDocumentation.documentationESQL.left.markdown": "\n\n ### LEFT\n Renvoie la sous-chaîne qui extrait la \"longueur\" des caractères de la \"chaîne\" en partant de la gauche.\n\n ````\n FROM employees\n | KEEP last_name\n | EVAL left = LEFT(last_name, 3)\n | SORT last_name ASC\n | LIMIT 5\n ````\n ", + "languageDocumentation.documentationESQL.left.markdown": " ### LEFT Renvoie la sous-chaîne qui extrait la \"longueur\" des caractères de la \"chaîne\" en partant de la gauche. ``` FROM employees | KEEP last_name | EVAL left = LEFT(last_name, 3) | SORT last_name ASC | LIMIT 5 ```", "languageDocumentation.documentationESQL.length": "LENGHT", - "languageDocumentation.documentationESQL.length.markdown": "\n\n ### LENGTH\n Renvoie la longueur des caractères d'une chaîne.\n\n ````\n FROM employees\n | KEEP first_name, last_name\n | EVAL fn_length = LENGTH(first_name)\n ````\n ", + "languageDocumentation.documentationESQL.length.markdown": " ### LENGTH Renvoie la longueur des caractères d'une chaîne. ``` FROM employees | KEEP first_name, last_name | EVAL fn_length = LENGTH(first_name) ```", "languageDocumentation.documentationESQL.limit": "LIMIT", - "languageDocumentation.documentationESQL.limit.markdown": "### LIMIT\nLa commande de traitement `LIMIT` permet de restreindre le nombre de lignes :\n \n````\nFROM employees\n| LIMIT 5\n````\n ", + "languageDocumentation.documentationESQL.limit.markdown": "### LIMIT La commande de traitement `LIMIT` permet de restreindre le nombre de lignes : ``` FROM employees | LIMIT 5 ```", "languageDocumentation.documentationESQL.locate": "LOCATE", - "languageDocumentation.documentationESQL.locate.markdown": "\n\n ### LOCATE\n Renvoie un entier qui indique la position d'une sous-chaîne de mots-clés dans une autre chaîne\n\n ````\n row a = \"hello\"\n | eval a_ll = locate(a, \"ll\")\n ````\n ", + "languageDocumentation.documentationESQL.locate.markdown": " ### LOCATE Renvoie un entier qui indique la position d'une sous-chaîne de mots-clés dans une autre chaîne. Renvoie `0` si la sous-chaîne ne peut pas être trouvée. Notez que les positions des chaînes commencent à partir de `1`. ``` row a = \"hello\" | eval a_ll = locate(a, \"ll\") ```", "languageDocumentation.documentationESQL.log": "LOG", - "languageDocumentation.documentationESQL.log.markdown": "\n\n ### LOG\n Renvoie le logarithme d'une valeur dans une base. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée.\n\n Les journaux de zéros, de nombres négatifs et de base 1 renvoient `null` ainsi qu'un avertissement.\n\n ````\n ROW base = 2.0, value = 8.0\n | EVAL s = LOG(base, value)\n ````\n ", + "languageDocumentation.documentationESQL.log.markdown": " ### LOG Renvoie le logarithme d'une valeur dans une base. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée. Les logs de zéros, de nombres négatifs et de base 1 renvoient `null` ainsi qu'un avertissement. ``` ROW base = 2.0, value = 8.0 | EVAL s = LOG(base, value) ```", "languageDocumentation.documentationESQL.log10": "LOG10", - "languageDocumentation.documentationESQL.log10.markdown": "\n\n ### LOG10\n Renvoie le logarithme d'une valeur en base 10. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée.\n\n Les logs de 0 et de nombres négatifs renvoient `null` ainsi qu'un avertissement.\n\n ````\n ROW d = 1000.0 \n | EVAL s = LOG10(d)\n ````\n ", + "languageDocumentation.documentationESQL.log10.markdown": " ### LOG10 Renvoie le logarithme d'une valeur en base 10. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée. Les logs de 0 et de nombres négatifs renvoient `null` ainsi qu'un avertissement. ``` ROW d = 1000.0 | EVAL s = LOG10(d) ```", "languageDocumentation.documentationESQL.ltrim": "LTRIM", - "languageDocumentation.documentationESQL.ltrim.markdown": "\n\n ### LTRIM\n Retire les espaces au début des chaînes.\n\n ````\n ROW message = \" some text \", color = \" red \"\n | EVAL message = LTRIM(message)\n | EVAL color = LTRIM(color)\n | EVAL message = CONCAT(\"'\", message, \"'\")\n | EVAL color = CONCAT(\"'\", color, \"'\")\n ````\n ", - "languageDocumentation.documentationESQL.markdown": "## ES|QL\n\nUne requête ES|QL (langage de requête Elasticsearch) se compose d'une série de commandes, séparées par une barre verticale : `|`. Chaque requête commence par une **commande source**, qui produit un tableau, habituellement avec des données issues d'Elasticsearch. \n\nUne commande source peut être suivie d'une ou plusieurs **commandes de traitement**. Les commandes de traitement peuvent modifier le tableau de sortie de la commande précédente en ajoutant, supprimant ou modifiant les lignes et les colonnes.\n\n````\nsource-command\n| processing-command1\n| processing-command2\n````\n\nLe résultat d'une requête est le tableau produit par la dernière commande de traitement. \n ", + "languageDocumentation.documentationESQL.ltrim.markdown": " ### LTRIM Supprime les espaces au début d'une chaîne. ``` ROW message = \" some text \", color = \" red \" | EVAL message = LTRIM(message) | EVAL color = LTRIM(color) | EVAL message = CONCAT(\"'\", message, \"'\") | EVAL color = CONCAT(\"'\", color, \"'\") ```", + "languageDocumentation.documentationESQL.markdown": "Une requête ES|QL (langage de requête Elasticsearch) se compose d'une série de commandes, séparées par une barre verticale : `|`. Chaque requête commence par une **commande source**, qui produit un tableau, habituellement avec des données issues d'Elasticsearch. Une commande source peut être suivie d'une ou plusieurs **commandes de traitement**. Les commandes de traitement peuvent modifier le tableau de sortie de la commande précédente en ajoutant, supprimant ou modifiant les lignes et les colonnes. ``` source-command | processing-command1 | processing-command2 ``` Le résultat d'une requête est le tableau produit par la dernière commande de traitement.", + "languageDocumentation.documentationESQL.max": "MAX", + "languageDocumentation.documentationESQL.max.markdown": " ### MAX La valeur maximale d'un champ. ``` FROM employees | STATS MAX(languages) ```", + "languageDocumentation.documentationESQL.median": "MEDIAN", + "languageDocumentation.documentationESQL.median_absolute_deviation": "MEDIAN_ABSOLUTE_DEVIATION", + "languageDocumentation.documentationESQL.median_absolute_deviation.markdown": " ### MEDIAN_ABSOLUTE_DEVIATION Renvoie l'écart absolu médian, une mesure de la variabilité. Il s'agit d'un indicateur robuste, ce qui signifie qu'il est utile pour décrire des données qui peuvent présenter des valeurs aberrantes ou ne pas être normalement distribuées. Pour de telles données, il peut être plus descriptif que l'écart-type. Il est calculé comme la médiane de chaque écart de point de données par rapport à la médiane de l'ensemble de l'échantillon. Autrement dit, pour une variable aléatoire `X`, l'écart absolu médian est `median(|median(X) - X|)`. ``` FROM employees | STATS MEDIAN(salary), MEDIAN_ABSOLUTE_DEVIATION(salary) ``` Remarque : Comme `PERCENTILE`, `MEDIAN_ABSOLUTE_DEVIATION` est généralement approximatif.", + "languageDocumentation.documentationESQL.median.markdown": " ### MEDIAN La valeur qui est supérieure à la moitié de toutes les valeurs et inférieure à la moitié de toutes les valeurs, également connue sous le nom de `PERCENTILE` 50 %. ``` FROM employees | STATS MEDIAN(salary), PERCENTILE(salary, 50) ``` Remarque : Comme `PERCENTILE`, `MEDIAN` est généralement approximatif.", + "languageDocumentation.documentationESQL.min": "MIN", + "languageDocumentation.documentationESQL.min.markdown": " ### MIN La valeur minimale d'un champ. ``` FROM employees | STATS MIN(languages) ```", "languageDocumentation.documentationESQL.mv_append": "MV_APPEND", - "languageDocumentation.documentationESQL.mv_append.markdown": "\n\n ### MV_APPEND\n Concatène les valeurs de deux champs à valeurs multiples.\n\n ", + "languageDocumentation.documentationESQL.mv_append.markdown": " ### MV_APPEND Concatène les valeurs de deux champs à valeurs multiples.", "languageDocumentation.documentationESQL.mv_avg": "MV_AVG", - "languageDocumentation.documentationESQL.mv_avg.markdown": "\n\n ### MV_AVG\n Convertit un champ multivalué en un champ à valeur unique comprenant la moyenne de toutes les valeurs.\n\n ````\n ROW a=[3, 5, 1, 6]\n | EVAL avg_a = MV_AVG(a)\n ````\n ", + "languageDocumentation.documentationESQL.mv_avg.markdown": " ### MV_AVG Convertit un champ multivalué en un champ à valeur unique comprenant la moyenne de toutes les valeurs. ``` ROW a=[3, 5, 1, 6] | EVAL avg_a = MV_AVG(a) ```", "languageDocumentation.documentationESQL.mv_concat": "MV_CONCAT", - "languageDocumentation.documentationESQL.mv_concat.markdown": "\n\n ### MV_CONCAT\n Convertit une expression de type chaîne multivalué en une colonne à valeur unique comprenant la concaténation de toutes les valeurs, séparées par un délimiteur.\n\n ````\n ROW a=[\"foo\", \"zoo\", \"bar\"]\n | EVAL j = MV_CONCAT(a, \", \")\n ````\n ", + "languageDocumentation.documentationESQL.mv_concat.markdown": " ### MV_CONCAT Convertit une expression de type chaîne multivaluée en une colonne à valeur unique comprenant la concaténation de toutes les valeurs, séparées par un délimiteur. ``` ROW a=[\"foo\", \"zoo\", \"bar\"] | EVAL j = MV_CONCAT(a, \", \") ```", "languageDocumentation.documentationESQL.mv_count": "MV_COUNT", - "languageDocumentation.documentationESQL.mv_count.markdown": "\n\n ### MV_COUNT\n Convertit une expression multivaluée en une colonne à valeur unique comprenant le total du nombre de valeurs.\n\n ````\n ROW a=[\"foo\", \"zoo\", \"bar\"]\n | EVAL count_a = MV_COUNT(a)\n ````\n ", + "languageDocumentation.documentationESQL.mv_count.markdown": " ### MV_COUNT Convertit une expression multivaluée en une colonne à valeur unique comprenant un décompte du nombre de valeurs. ``` ROW a=[\"foo\", \"zoo\", \"bar\"] | EVAL count_a = MV_COUNT(a) ```", "languageDocumentation.documentationESQL.mv_dedupe": "MV_DEDUPE", - "languageDocumentation.documentationESQL.mv_dedupe.markdown": "\n\n ### MV_DEDUPE\n Supprime les valeurs en doublon d'un champ multivalué.\n\n ````\n ROW a=[\"foo\", \"foo\", \"bar\", \"foo\"]\n | EVAL dedupe_a = MV_DEDUPE(a)\n ````\n Remarque : la fonction `MV_DEDUPE` est en mesure de trier les valeurs de la colonne, mais ne le fait pas systématiquement.\n ", + "languageDocumentation.documentationESQL.mv_dedupe.markdown": " ### MV_DEDUPE Supprime les valeurs en doublon d'un champ multivalué. ``` ROW a=[\"foo\", \"foo\", \"bar\", \"foo\"] | EVAL dedupe_a = MV_DEDUPE(a) ``` Remarque : La fonction `MV_DEDUPE` est en mesure de trier les valeurs de la colonne, mais ne le fait pas systématiquement.", "languageDocumentation.documentationESQL.mv_first": "MV_FIRST", - "languageDocumentation.documentationESQL.mv_first.markdown": "\n\n ### MV_FIRST\n Convertit une expression multivaluée en une colonne à valeur unique comprenant la\n première valeur. Ceci est particulièrement utile pour lire une fonction qui émet\n des colonnes multivaluées dans un ordre connu, comme `SPLIT`.\n\n L'ordre dans lequel les champs multivalués sont lus à partir\n du stockage sous-jacent n'est pas garanti. Il est *souvent* ascendant, mais ne vous y\n fiez pas. Si vous avez besoin de la valeur minimale, utilisez `MV_MIN` au lieu de\n `MV_FIRST`. `MV_MIN` comporte des optimisations pour les valeurs triées, il n'y a donc aucun\n avantage en matière de performances pour `MV_FIRST`.\n\n ````\n ROW a=\"foo;bar;baz\"\n | EVAL first_a = MV_FIRST(SPLIT(a, \";\"))\n ````\n ", + "languageDocumentation.documentationESQL.mv_first.markdown": " ### MV_FIRST Convertit une expression multivaluée en une colonne à valeur unique comprenant la valeur minimale. Ceci est particulièrement utile pour lire une fonction qui émet des colonnes multivaluées dans un ordre connu, comme `SPLIT`. ``` ROW a=\"foo;bar;baz\" | EVAL first_a = MV_FIRST(SPLIT(a, \";\")) ```", "languageDocumentation.documentationESQL.mv_last": "MV_LAST", - "languageDocumentation.documentationESQL.mv_last.markdown": "\n\n ### MV_LAST\n Convertit une expression multivaluée en une colonne à valeur unique comprenant la dernière\n valeur. Ceci est particulièrement utile pour lire une fonction qui émet des champs multivalués\n dans un ordre connu, comme `SPLIT`.\n\n L'ordre dans lequel les champs multivalués sont lus à partir\n du stockage sous-jacent n'est pas garanti. Il est *souvent* ascendant, mais ne vous y\n fiez pas. Si vous avez besoin de la valeur maximale, utilisez `MV_MAX` au lieu de\n `MV_LAST`. `MV_MAX` comporte des optimisations pour les valeurs triées, il n'y a donc aucun\n avantage en matière de performances pour `MV_LAST`.\n\n ````\n ROW a=\"foo;bar;baz\"\n | EVAL last_a = MV_LAST(SPLIT(a, \";\"))\n ````\n ", + "languageDocumentation.documentationESQL.mv_last.markdown": " ### MV_LAST Convertit une expression multivaluée en une colonne à valeur unique comprenant la dernière valeur. Ceci est particulièrement utile pour lire une fonction qui émet des colonnes multivaluées dans un ordre connu, comme `SPLIT`. ``` ROW a=\"foo;bar;baz\" | EVAL last_a = MV_LAST(SPLIT(a, \";\")) ```", "languageDocumentation.documentationESQL.mv_max": "MV_MAX", - "languageDocumentation.documentationESQL.mv_max.markdown": "\n\n ### MV_MAX\n Convertit une expression multivaluée en une colonne à valeur unique comprenant la valeur maximale.\n\n ````\n ROW a=[3, 5, 1]\n | EVAL max_a = MV_MAX(a)\n ````\n ", + "languageDocumentation.documentationESQL.mv_max.markdown": " ### MV_MAX Convertit une expression multivaluée en une colonne à valeur unique comprenant la valeur maximale. ``` ROW a=[3, 5, 1] | EVAL max_a = MV_MAX(a) ```", "languageDocumentation.documentationESQL.mv_median": "MV_MEDIAN", - "languageDocumentation.documentationESQL.mv_median.markdown": "\n\n ### MV_MEDIAN\n Convertit un champ multivalué en un champ à valeur unique comprenant la valeur médiane.\n\n ````\n ROW a=[3, 5, 1]\n | EVAL median_a = MV_MEDIAN(a)\n ````\n ", + "languageDocumentation.documentationESQL.mv_median_absolute_deviation": "MV_MEDIAN_ABSOLUTE_DEVIATION", + "languageDocumentation.documentationESQL.mv_median_absolute_deviation.markdown": " ### MV_MEDIAN_ABSOLUTE_DEVIATION Convertit un champ multivalué en un champ à valeur unique comprenant l'écart absolu médian. Il est calculé comme la médiane de chaque écart de point de données par rapport à la médiane de l'ensemble de l'échantillon. Autrement dit, pour une variable aléatoire `X`, l'écart absolu médian est `median(|median(X) - X|)`. ``` ROW values = [0, 2, 5, 6] | EVAL median_absolute_deviation = MV_MEDIAN_ABSOLUTE_DEVIATION(values), median = MV_MEDIAN(values) ``` Remarque : Si le champ a un nombre pair de valeurs, les médianes seront calculées comme la moyenne des deux valeurs du milieu. Si la valeur n'est pas un nombre à virgule flottante, les moyennes sont arrondies vers 0.", + "languageDocumentation.documentationESQL.mv_median.markdown": " ### MV_MEDIAN Convertit un champ multivalué en un champ à valeur unique comprenant la valeur médiane. ``` ROW a=[3, 5, 1] | EVAL median_a = MV_MEDIAN(a) ```", "languageDocumentation.documentationESQL.mv_min": "MV_MIN", - "languageDocumentation.documentationESQL.mv_min.markdown": "\n\n ### MV_MIN\n Convertit une expression multivaluée en une colonne à valeur unique comprenant la valeur minimale.\n\n ````\n ROW a=[2, 1]\n | EVAL min_a = MV_MIN(a)\n ````\n ", + "languageDocumentation.documentationESQL.mv_min.markdown": " ### MV_MIN Convertit une expression multivaluée en une colonne à valeur unique comprenant la valeur minimale. ``` ROW a=[2, 1] | EVAL min_a = MV_MIN(a) ```", + "languageDocumentation.documentationESQL.mv_percentile": "MV_PERCENTILE", + "languageDocumentation.documentationESQL.mv_percentile.markdown": " ### MV_PERCENTILE Convertit un champ multivalué en un champ à valeur unique comprenant la valeur à laquelle un certain pourcentage des valeurs observées se produit. ``` ROW values = [5, 5, 10, 12, 5000] | EVAL p50 = MV_PERCENTILE(values, 50), median = MV_MEDIAN(values) ```", + "languageDocumentation.documentationESQL.mv_pseries_weighted_sum": "MV_PSERIES_WEIGHTED_SUM", + "languageDocumentation.documentationESQL.mv_pseries_weighted_sum.markdown": " ### MV_PSERIES_WEIGHTED_SUM Convertit une expression multivaluée en une colonne à valeur unique en multipliant chaque élément de la liste d'entrée par le terme correspondant dans P-Series et en calculant la somme. ``` ROW a = [70.0, 45.0, 21.0, 21.0, 21.0] | EVAL sum = MV_PSERIES_WEIGHTED_SUM(a, 1.5) | KEEP sum ```", "languageDocumentation.documentationESQL.mv_slice": "MV_SLICE", - "languageDocumentation.documentationESQL.mv_slice.markdown": "\n\n ### MV_SLICE\n Renvoie un sous-ensemble du champ multivalué en utilisant les valeurs d'index de début et de fin.\n\n ````\n row a = [1, 2, 2, 3]\n | eval a1 = mv_slice(a, 1), a2 = mv_slice(a, 2, 3)\n ````\n ", + "languageDocumentation.documentationESQL.mv_slice.markdown": " ### MV_SLICE Renvoie un sous-ensemble du champ multivalué en utilisant les valeurs d'index de début et de fin. Ceci est particulièrement utile pour lire une fonction qui émet des colonnes multivaluées dans un ordre connu, comme `SPLIT` ou `MV_SORT`. ``` row a = [1, 2, 2, 3] | eval a1 = mv_slice(a, 1), a2 = mv_slice(a, 2, 3) ```", "languageDocumentation.documentationESQL.mv_sort": "MV_SORT", - "languageDocumentation.documentationESQL.mv_sort.markdown": "\n\n ### MV_SORT\n Trie une expression multivaluée par ordre lexicographique.\n\n ````\n ROW a = [4, 2, -3, 2]\n | EVAL sa = mv_sort(a), sd = mv_sort(a, \"DESC\")\n ````\n ", + "languageDocumentation.documentationESQL.mv_sort.markdown": " ### MV_SORT Trie un champ multivalué par ordre lexicographique. ``` ROW a = [4, 2, -3, 2] | EVAL sa = mv_sort(a), sd = mv_sort(a, \"DESC\") ```", "languageDocumentation.documentationESQL.mv_sum": "MV_SUM", - "languageDocumentation.documentationESQL.mv_sum.markdown": "\n\n ### MV_SUM\n Convertit un champ multivalué en un champ à valeur unique comprenant la somme de toutes les valeurs.\n\n ````\n ROW a=[3, 5, 6]\n | EVAL sum_a = MV_SUM(a)\n ````\n ", + "languageDocumentation.documentationESQL.mv_sum.markdown": " ### MV_SUM Convertit un champ multivalué en un champ à valeur unique comprenant la somme de toutes les valeurs. ``` ROW a=[3, 5, 6] | EVAL sum_a = MV_SUM(a) ```", "languageDocumentation.documentationESQL.mv_zip": "MV_ZIP", - "languageDocumentation.documentationESQL.mv_zip.markdown": "\n\n ### MV_ZIP\n Combine les valeurs de deux champs multivalués avec un délimiteur qui les relie.\n\n ````\n ROW a = [\"x\", \"y\", \"z\"], b = [\"1\", \"2\"]\n | EVAL c = mv_zip(a, b, \"-\")\n | KEEP a, b, c\n ````\n ", + "languageDocumentation.documentationESQL.mv_zip.markdown": " ### MV_ZIP Combine les valeurs de deux champs multivalués avec un délimiteur qui les relie. ``` ROW a = [\"x\", \"y\", \"z\"], b = [\"1\", \"2\"] | EVAL c = mv_zip(a, b, \"-\") | KEEP a, b, c ```", "languageDocumentation.documentationESQL.mvExpand": "MV_EXPAND", - "languageDocumentation.documentationESQL.mvExpand.markdown": "### MV_EXPAND\nLa commande de traitement `MV_EXPAND` développe les champs multivalués en indiquant une valeur par ligne et en dupliquant les autres champs : \n````\nROW a=[1,2,3], b=\"b\", j=[\"a\",\"b\"]\n| MV_EXPAND a\n````\n ", + "languageDocumentation.documentationESQL.mvExpand.markdown": "### MV_EXPAND La commande de traitement `MV_EXPAND` développe les champs multivalués en indiquant une valeur par ligne et en dupliquant les autres champs : ``` ROW a=[1,2,3], b=\"b\", j=[\"a\",\"b\"] | MV_EXPAND a ```", "languageDocumentation.documentationESQL.now": "NOW", - "languageDocumentation.documentationESQL.now.markdown": "\n\n ### NOW\n Renvoie la date et l'heure actuelles.\n\n ````\n ROW current_date = NOW()\n ````\n ", + "languageDocumentation.documentationESQL.now.markdown": " ### NOW Renvoie la date et l'heure actuelles. ``` ROW current_date = NOW() ```", "languageDocumentation.documentationESQL.operators": "Opérateurs", "languageDocumentation.documentationESQL.operatorsDocumentationESQLDescription": "ES|QL est compatible avec les opérateurs suivants :", + "languageDocumentation.documentationESQL.percentile": "PERCENTILE", + "languageDocumentation.documentationESQL.percentile.markdown": " ### PERCENTILE Renvoie la valeur à laquelle un certain pourcentage des valeurs observées se produit. Par exemple, le 95e percentile est la valeur qui est supérieure à 95 % des valeurs observées et le 50percentile est la médiane (`MEDIAN`). ``` FROM employees | STATS p0 = PERCENTILE(salary, 0) , p50 = PERCENTILE(salary, 50) , p99 = PERCENTILE(salary, 99) ```", "languageDocumentation.documentationESQL.pi": "PI", - "languageDocumentation.documentationESQL.pi.markdown": "\n\n ### PI\n Renvoie Pi, le rapport entre la circonférence et le diamètre d'un cercle.\n\n ````\n ROW PI()\n ````\n ", + "languageDocumentation.documentationESQL.pi.markdown": " ### PI Renvoie Pi, le rapport entre la circonférence et le diamètre d'un cercle. ``` ROW PI() ```", "languageDocumentation.documentationESQL.pow": "POW", - "languageDocumentation.documentationESQL.pow.markdown": "\n\n ### POW\n Renvoie la valeur d’une `base` élevée à la puissance d’un `exposant`.\n\n ````\n ROW base = 2.0, exponent = 2\n | EVAL result = POW(base, exponent)\n ````\n Remarque : Il est toujours possible de dépasser un résultat double ici ; dans ce cas, la valeur `null` sera renvoyée.\n ", + "languageDocumentation.documentationESQL.pow.markdown": " ### POW Renvoie la valeur d'une `base` élevée à la puissance d'un exposant (`exponent`). ``` ROW base = 2.0, exponent = 2 | EVAL result = POW(base, exponent) ``` Remarque : Il est toujours possible de dépasser un résultat double ici ; dans ce cas, la valeur `null` sera renvoyée.", "languageDocumentation.documentationESQL.predicates": "valeurs NULL", - "languageDocumentation.documentationESQL.predicates.markdown": "### Valeurs NULL\nPour une comparaison avec une valeur NULL, utilisez les attributs `IS NULL` et `IS NOT NULL` :\n\n````\nFROM employees\n| WHERE birth_date IS NULL\n| KEEP first_name, last_name\n| SORT first_name\n| LIMIT 3\n````\n\n````\nFROM employees\n| WHERE is_rehired IS NOT NULL\n| STATS count(emp_no)\n````\n ", + "languageDocumentation.documentationESQL.predicates.markdown": "### Valeurs NULL Pour une comparaison avec une valeur NULL, utilisez les attributs `IS NULL` et `IS NOT NULL` : ``` FROM employees | WHERE birth_date IS NULL | KEEP first_name, last_name | SORT first_name | LIMIT 3 ``` ``` FROM employees | WHERE is_rehired IS NOT NULL | STATS count(emp_no) ```", "languageDocumentation.documentationESQL.processingCommands": "Traitement des commandes", "languageDocumentation.documentationESQL.processingCommandsDescription": "Le traitement des commandes transforme un tableau des entrées par l'ajout, le retrait ou la modification des lignes et des colonnes. ES|QL est compatible avec le traitement des commandes suivant.", "languageDocumentation.documentationESQL.rename": "RENAME", - "languageDocumentation.documentationESQL.rename.markdown": "### RENAME\nUtilisez `RENAME` pour renommer une colonne en utilisant la syntaxe suivante :\n\n````\nRENAME AS \n````\n\nPar exemple :\n\n````\nFROM employees\n| KEEP first_name, last_name, still_hired\n| RENAME still_hired AS employed\n````\n\nSi une colonne portant le nouveau nom existe déjà, elle sera remplacée par la nouvelle colonne.\n\nPlusieurs colonnes peuvent être renommées à l'aide d'une seule commande `RENAME` :\n\n````\nFROM employees\n| KEEP first_name, last_name\n| RENAME first_name AS fn, last_name AS ln\n````\n ", + "languageDocumentation.documentationESQL.rename.markdown": "### RENAME Utilisez `RENAME` pour renommer une colonne en utilisant la syntaxe suivante : ``` RENAME AS ``` For example: ``` FROM employees | KEEP first_name, last_name, still_hired | RENAME still_hired AS employed ``` If a column with the new name already exists, it will be replaced by the new column. Multiple columns can be renamed with a single `RENAME` command: ``` FROM employees | KEEP first_name, last_name | RENAME first_name AS fn, last_name AS ln ```", "languageDocumentation.documentationESQL.repeat": "REPEAT", - "languageDocumentation.documentationESQL.repeat.markdown": "\n\n ### REPEAT\n Renvoie une chaîne construite par la concaténation de la `chaîne` avec elle-même, le `nombre` de fois spécifié.\n\n ````\n ROW a = \"Hello!\"\n | EVAL triple_a = REPEAT(a, 3);\n ````\n ", + "languageDocumentation.documentationESQL.repeat.markdown": " ### REPEAT Renvoie une chaîne construite par la concaténation de la chaîne (`string`) avec elle-même, le nombre (`number`) de fois spécifié. ``` ROW a = \"Hello!\" | EVAL triple_a = REPEAT(a, 3); ```", "languageDocumentation.documentationESQL.replace": "REPLACE", - "languageDocumentation.documentationESQL.replace.markdown": "\n\n ### REPLACE\n La fonction remplace dans la chaîne `str` toutes les correspondances avec l'expression régulière `regex`\n par la chaîne de remplacement `newStr`.\n\n ````\n ROW str = \"Hello World\"\n | EVAL str = REPLACE(str, \"World\", \"Universe\")\n | KEEP str\n ````\n ", + "languageDocumentation.documentationESQL.replace.markdown": " ### REPLACE La fonction remplace dans la chaîne `str` toutes les correspondances avec l'expression régulière `regex` par la chaîne de remplacement `newStr`. ``` ROW str = \"Hello World\" | EVAL str = REPLACE(str, \"World\", \"Universe\") | KEEP str ```", + "languageDocumentation.documentationESQL.reverse": "REVERSE", + "languageDocumentation.documentationESQL.reverse.markdown": " ### REVERSE Renvoie une nouvelle chaîne représentant la chaîne d'entrée dans l'ordre inverse. ``` ROW message = \"Some Text\" | EVAL message_reversed = REVERSE(message); ```", "languageDocumentation.documentationESQL.right": "RIGHT", - "languageDocumentation.documentationESQL.right.markdown": "\n\n ### RIGHT\n Renvoie la sous-chaîne qui extrait la longueur des caractères de `str` en partant de la droite.\n\n ````\n FROM employees\n | KEEP last_name\n | EVAL right = RIGHT(last_name, 3)\n | SORT last_name ASC\n | LIMIT 5\n ````\n ", + "languageDocumentation.documentationESQL.right.markdown": " ### RIGHT Renvoie la sous-chaîne qui extrait la \"longueur\" des caractères de `str` en partant de la droite. ``` FROM employees | KEEP last_name | EVAL right = RIGHT(last_name, 3) | SORT last_name ASC | LIMIT 5 ```", "languageDocumentation.documentationESQL.round": "ROUND", - "languageDocumentation.documentationESQL.round.markdown": "\n\n ### ROUND\n Arrondit un nombre au nombre spécifié de décimales.\n La valeur par défaut est 0, qui renvoie l'entier le plus proche. Si le\n nombre de décimales spécifié est négatif, la fonction arrondit au nombre de décimales à gauche\n de la virgule.\n\n ````\n FROM employees\n | KEEP first_name, last_name, height\n | EVAL height_ft = ROUND(height * 3.281, 1)\n ````\n ", + "languageDocumentation.documentationESQL.round.markdown": " ### ROUND Arrondit un nombre au nombre spécifié de décimales. La valeur par défaut est 0, qui renvoie l'entier le plus proche. Si le nombre de décimales spécifié est négatif, la fonction arrondit au nombre de décimales à gauche. ``` FROM employees | KEEP first_name, last_name, height | EVAL height_ft = ROUND(height * 3.281, 1) ```", "languageDocumentation.documentationESQL.row": "ROW", - "languageDocumentation.documentationESQL.row.markdown": "### ROW\nLa commande source `ROW` renvoie une ligne contenant une ou plusieurs colonnes avec les valeurs que vous spécifiez. Cette commande peut s'avérer utile pour les tests.\n \n````\nROW a = 1, b = \"two\", c = null\n````\n\nUtilisez des crochets pour créer des colonnes à valeurs multiples :\n\n````\nROW a = [2, 1]\n````\n\nROW permet d'utiliser des fonctions :\n\n````\nROW a = ROUND(1.23, 0)\n````\n ", + "languageDocumentation.documentationESQL.row.markdown": "### ROW La commande source `ROW` renvoie une ligne contenant une ou plusieurs colonnes avec les valeurs que vous spécifiez. Cette commande peut s'avérer utile pour les tests. ``` ROW a = 1, b = \"two\", c = null ``` Utilisez des crochets pour créer des colonnes à valeurs multiples : ``` ROW a = [2, 1] ``` ROW permet d'utiliser des fonctions : ``` ROW a = ROUND(1.23, 0) ```", "languageDocumentation.documentationESQL.rtrim": "RTRIM", - "languageDocumentation.documentationESQL.rtrim.markdown": "\n\n ### RTRIM\n Supprime les espaces à la fin des chaînes.\n\n ````\n ROW message = \" some text \", color = \" red \"\n | EVAL message = RTRIM(message)\n | EVAL color = RTRIM(color)\n | EVAL message = CONCAT(\"'\", message, \"'\")\n | EVAL color = CONCAT(\"'\", color, \"'\")\n ````\n ", + "languageDocumentation.documentationESQL.rtrim.markdown": " ### RTRIM Supprime les espaces à la fin d'une chaîne. ``` ROW message = \" some text \", color = \" red \" | EVAL message = RTRIM(message) | EVAL color = RTRIM(color) | EVAL message = CONCAT(\"'\", message, \"'\") | EVAL color = CONCAT(\"'\", color, \"'\") ```", "languageDocumentation.documentationESQL.show": "SHOW", - "languageDocumentation.documentationESQL.show.markdown": "### SHOW\nLa commande source `SHOW ` renvoie des informations sur le déploiement et ses capacités :\n\n* Utilisez `SHOW INFO` pour renvoyer la version du déploiement, la date de compilation et le hachage.\n* Utilisez `SHOW FUNCTIONS` pour renvoyer une liste de toutes les fonctions prises en charge et un résumé de chaque fonction.\n ", + "languageDocumentation.documentationESQL.show.markdown": "### SHOW La commande source `SHOW ` renvoie des informations sur le déploiement et ses capacités : * Utilisez `SHOW INFO` pour renvoyer la version du déploiement, la date de compilation et le hachage. * Utilisez `SHOW FUNCTIONS` pour renvoyer une liste de toutes les fonctions prises en charge et un résumé de chaque fonction.", "languageDocumentation.documentationESQL.signum": "SIGNUM", - "languageDocumentation.documentationESQL.signum.markdown": "\n\n ### SIGNUM\n Renvoie le signe du nombre donné.\n Il renvoie `-1` pour les nombres négatifs, `0` pour `0` et `1` pour les nombres positifs.\n\n ````\n ROW d = 100.0\n | EVAL s = SIGNUM(d)\n ````\n ", + "languageDocumentation.documentationESQL.signum.markdown": " ### SIGNUM Renvoie le signe du nombre donné. Renvoie `-1` pour les nombres négatifs, `0` pour `0` et `1` pour les nombres positifs. ``` ROW d = 100.0 | EVAL s = SIGNUM(d) ```", "languageDocumentation.documentationESQL.sin": "SIN", - "languageDocumentation.documentationESQL.sin.markdown": "\n\n ### SIN\n Renvoie la fonction trigonométrique sinusoïdale d'un angle.\n\n ````\n ROW a=1.8 \n | EVAL sin=SIN(a)\n ````\n ", + "languageDocumentation.documentationESQL.sin.markdown": " ### SIN Renvoie le sinus d'un angle. ``` ROW a=1.8 | EVAL sin=SIN(a) ```", "languageDocumentation.documentationESQL.sinh": "SINH", - "languageDocumentation.documentationESQL.sinh.markdown": "\n\n ### SINH\n Renvoie le sinus hyperbolique d'un angle.\n\n ````\n ROW a=1.8 \n | EVAL sinh=SINH(a)\n ````\n ", + "languageDocumentation.documentationESQL.sinh.markdown": " ### SINH Renvoie le sinus hyperbolique d'un nombre. ``` ROW a=1.8 | EVAL sinh=SINH(a) ```", "languageDocumentation.documentationESQL.sort": "SORT", - "languageDocumentation.documentationESQL.sort.markdown": "### SORT\nUtilisez la commande `SORT` pour trier les lignes sur un ou plusieurs champs :\n\n````\nFROM employees\n| KEEP first_name, last_name, height\n| SORT height\n````\n\nL'ordre de tri par défaut est croissant. Définissez un ordre de tri explicite en utilisant `ASC` ou `DESC` :\n\n````\nFROM employees\n| KEEP first_name, last_name, height\n| SORT height DESC\n````\n\nSi deux lignes disposent de la même clé de tri, l'ordre original sera préservé. Vous pouvez ajouter des expressions de tri pour départager les deux lignes :\n\n````\nFROM employees\n| KEEP first_name, last_name, height\n| SORT height DESC, first_name ASC\n````\n\n#### valeurs `null`\nPar défaut, les valeurs `null` sont considérées comme étant supérieures à toutes les autres valeurs. Selon un ordre de tri croissant, les valeurs `null` sont classées en dernier. Selon un ordre de tri décroissant, les valeurs `null` sont classées en premier. Pour modifier cet ordre, utilisez `NULLS FIRST` ou `NULLS LAST` :\n\n````\nFROM employees\n| KEEP first_name, last_name, height\n| SORT first_name ASC NULLS FIRST\n````\n ", + "languageDocumentation.documentationESQL.sort.markdown": "### SORT Utilisez la commande `SORT` pour trier les lignes sur un ou plusieurs champs : ``` FROM employees | KEEP first_name, last_name, height | SORT height ``` L'ordre de tri par défaut est croissant. Définissez un ordre de tri explicite en utilisant `ASC` ou `DESC` : ``` FROM employees | KEEP first_name, last_name, height | SORT height DESC ``` Si deux lignes disposent de la même clé de tri, l'ordre original sera préservé. Vous pouvez ajouter des expressions de tri pour départager les deux lignes : ``` FROM employees | KEEP first_name, last_name, height | SORT height DESC, first_name ASC ``` #### Valeurs `null` Par défaut, les valeurs `null` sont considérées comme étant supérieures à toutes les autres valeurs. Selon un ordre de tri croissant, les valeurs `null` sont classées en dernier. Selon un ordre de tri décroissant, les valeurs `null` sont classées en premier. Pour modifier cet ordre, utilisez `NULLS FIRST` ou `NULLS LAST` : ``` FROM employees | KEEP first_name, last_name, height | SORT first_name ASC NULLS FIRST ```", "languageDocumentation.documentationESQL.sourceCommands": "Commandes sources", + "languageDocumentation.documentationESQL.space": "SPACE", + "languageDocumentation.documentationESQL.space.markdown": " ### SPACE Renvoie une chaîne composée d'espaces nombre (`number`). ``` ROW message = CONCAT(\"Hello\", SPACE(1), \"World!\"); ```", "languageDocumentation.documentationESQL.split": "SPLIT", - "languageDocumentation.documentationESQL.split.markdown": "\n\n ### SPLIT\n Divise une chaîne de valeur unique en plusieurs chaînes.\n\n ````\n ROW words=\"foo;bar;baz;qux;quux;corge\"\n | EVAL word = SPLIT(words, \";\")\n ````\n ", + "languageDocumentation.documentationESQL.split.markdown": " ### SPLIT Divise une chaîne de valeur unique en plusieurs chaînes. ``` ROW words=\"foo;bar;baz;qux;quux;corge\" | EVAL word = SPLIT(words, \";\") ```", "languageDocumentation.documentationESQL.sqrt": "SQRT", - "languageDocumentation.documentationESQL.sqrt.markdown": "\n\n ### SQRT\n Renvoie la racine carrée d'un nombre. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée.\n Les racines carrées des nombres négatifs et des infinis sont nulles.\n\n ````\n ROW d = 100.0\n | EVAL s = SQRT(d)\n ````\n ", + "languageDocumentation.documentationESQL.sqrt.markdown": " ### SQRT Renvoie la racine carrée d'un nombre. La valeur de renvoi est toujours un double, quelle que soit la valeur numérique de l'entrée. Les racines carrées des nombres négatifs et des infinis sont nulles. ``` ROW d = 100.0 | EVAL s = SQRT(d) ```", + "languageDocumentation.documentationESQL.st_centroid_agg": "ST_CENTROID_AGG", + "languageDocumentation.documentationESQL.st_centroid_agg.markdown": " ### ST_CENTROID_AGG Calcule le centroïde spatial sur un champ avec un type de géométrie de point spatial. ``` FROM airports | STATS centroid=ST_CENTROID_AGG(location) ```", "languageDocumentation.documentationESQL.st_contains": "ST_CONTAINS", - "languageDocumentation.documentationESQL.st_contains.markdown": "\n\n ### ST_CONTAINS\n Renvoie si la première géométrie contient la deuxième géométrie.\n Il s'agit de l'inverse de la fonction `ST_WITHIN`.\n\n ````\n FROM airport_city_boundaries\n | WHERE ST_CONTAINS(city_boundary, TO_GEOSHAPE(\"POLYGON((109.35 18.3, 109.45 18.3, 109.45 18.4, 109.35 18.4, 109.35 18.3))\"))\n | KEEP abbrev, airport, region, city, city_location\n ````\n ", + "languageDocumentation.documentationESQL.st_contains.markdown": " ### ST_CONTAINS Renvoie si la première géométrie contient la deuxième géométrie. Il s'agit de l'inverse de la fonction `ST_WITHIN`. ``` FROM airport_city_boundaries | WHERE ST_CONTAINS(city_boundary, TO_GEOSHAPE(\"POLYGON((109.35 18.3, 109.45 18.3, 109.45 18.4, 109.35 18.4, 109.35 18.3))\")) | KEEP abbrev, airport, region, city, city_location ```", "languageDocumentation.documentationESQL.st_disjoint": "ST_DISJOINT", - "languageDocumentation.documentationESQL.st_disjoint.markdown": "\n\n ### ST_DISJOINT\n Renvoie si les deux géométries ou colonnes géométriques sont disjointes.\n Il s'agit de l'inverse de la fonction `ST_INTERSECTS`.\n En termes mathématiques : ST_Disjoint(A, B) ⇔ A ⋂ B = ∅\n\n ````\n FROM airport_city_boundaries\n | WHERE ST_DISJOINT(city_boundary, TO_GEOSHAPE(\"POLYGON((-10 -60, 120 -60, 120 60, -10 60, -10 -60))\"))\n | KEEP abbrev, airport, region, city, city_location\n ````\n ", + "languageDocumentation.documentationESQL.st_disjoint.markdown": " ### ST_DISJOINT Renvoie si les deux géométries ou colonnes géométriques sont disjointes. Il s'agit de l'inverse de la fonction `ST_INTERSECTS`. En termes mathématiques : ST_Disjoint(A, B) ⇔ A ⋂ B = ∅ ``` FROM airport_city_boundaries | WHERE ST_DISJOINT(city_boundary, TO_GEOSHAPE(\"POLYGON((-10 -60, 120 -60, 120 60, -10 60, -10 -60))\")) | KEEP abbrev, airport, region, city, city_location ```", "languageDocumentation.documentationESQL.st_distance": "ST_DISTANCE", - "languageDocumentation.documentationESQL.st_distance.markdown": "\n\n ### ST_DISTANCE\n Calcule la distance entre deux points.\n Pour les géométries cartésiennes, c’est la distance pythagoricienne dans les mêmes unités que les coordonnées d'origine.\n Pour les géométries géographiques, c’est la distance circulaire le long du grand cercle en mètres.\n\n ````\n Aéroports FROM\n | WHERE abbrev == \"CPH\"\n | EVAL distance = ST_DISTANCE(location, city_location)\n | KEEP abbrev, name, location, city_location, distance\n ````\n ", + "languageDocumentation.documentationESQL.st_distance.markdown": " ### ST_DISTANCE Calcule la distance entre deux points. Pour les géométries cartésiennes, c’est la distance pythagoricienne dans les mêmes unités que les coordonnées d'origine. Pour les géométries géographiques, c'est la distance circulaire le long du grand cercle en mètres. ``` FROM airports | WHERE abbrev == \"CPH\" | EVAL distance = ST_DISTANCE(location, city_location) | KEEP abbrev, name, location, city_location, distance ```", "languageDocumentation.documentationESQL.st_intersects": "ST_INTERSECTS", - "languageDocumentation.documentationESQL.st_intersects.markdown": "\n\n ### ST_INTERSECTS\n Renvoie `true` (vrai) si deux géométries se croisent.\n Elles se croisent si elles ont un point commun, y compris leurs points intérieurs\n (les points situés le long des lignes ou dans des polygones).\n Il s'agit de l'inverse de la fonction `ST_DISJOINT`.\n En termes mathématiques : ST_Intersects(A, B) ⇔ A ⋂ B ≠ ∅\n\n ````\n Aéroports FROM\n | WHERE ST_INTERSECTS(location, TO_GEOSHAPE(\"POLYGON((42 14, 43 14, 43 15, 42 15, 42 14))\"))\n ````\n ", + "languageDocumentation.documentationESQL.st_intersects.markdown": " ### ST_INTERSECTS Renvoie `true` (vrai) si deux géométries se croisent. Elles se croisent si elles ont un point commun, y compris leurs points intérieurs (points le long de lignes ou à l'intérieur de polygones). Il s'agit de l'inverse de la fonction `ST_DISJOINT`. En termes mathématiques : ST_Intersects(A, B) ⇔ A ⋂ B ≠ ∅ ``` FROM airports | WHERE ST_INTERSECTS(location, TO_GEOSHAPE(\"POLYGON((42 14, 43 14, 43 15, 42 15, 42 14))\")) ```", "languageDocumentation.documentationESQL.st_within": "ST_WITHIN", - "languageDocumentation.documentationESQL.st_within.markdown": "\n\n ### ST_WITHIN\n Renvoie si la première géométrie est à l'intérieur de la deuxième géométrie.\n Il s'agit de l'inverse de la fonction `ST_CONTAINS`.\n\n ````\n FROM airport_city_boundaries\n | WHERE ST_WITHIN(city_boundary, TO_GEOSHAPE(\"POLYGON((109.1 18.15, 109.6 18.15, 109.6 18.65, 109.1 18.65, 109.1 18.15))\"))\n | KEEP abbrev, airport, region, city, city_location\n ````\n ", + "languageDocumentation.documentationESQL.st_within.markdown": " ### ST_WITHIN Renvoie si la première géométrie est comprise dans la deuxième géométrie. Il s'agit de l'inverse de la fonction `ST_CONTAINS`. ``` FROM airport_city_boundaries | WHERE ST_WITHIN(city_boundary, TO_GEOSHAPE(\"POLYGON((109.1 18.15, 109.6 18.15, 109.6 18.65, 109.1 18.65, 109.1 18.15))\")) | KEEP abbrev, airport, region, city, city_location ```", "languageDocumentation.documentationESQL.st_x": "ST_X", - "languageDocumentation.documentationESQL.st_x.markdown": "\n\n ### ST_X\n Extrait la coordonnée `x` du point fourni.\n Si les points sont de type `geo_point`, cela revient à extraire la valeur de la `longitude`.\n\n ````\n ROW point = TO_GEOPOINT(\"POINT(42.97109629958868 14.7552534006536)\")\n | EVAL x = ST_X(point), y = ST_Y(point)\n ````\n ", + "languageDocumentation.documentationESQL.st_x.markdown": " ### ST_X Extrait la coordonnée `x` du point fourni. Si les points sont de type `geo_point`, cela revient à extraire la valeur de la `longitude`. ``` ROW point = TO_GEOPOINT(\"POINT(42.97109629958868 14.7552534006536)\") | EVAL x = ST_X(point), y = ST_Y(point) ```", "languageDocumentation.documentationESQL.st_y": "ST_Y", - "languageDocumentation.documentationESQL.st_y.markdown": "\n\n ### ST_Y\n Extrait la coordonnée `y` du point fourni.\n Si les points sont de type `geo_point`, cela revient à extraire la valeur de la `latitude`.\n\n ````\n ROW point = TO_GEOPOINT(\"POINT(42.97109629958868 14.7552534006536)\")\n | EVAL x = ST_X(point), y = ST_Y(point)\n ````\n ", + "languageDocumentation.documentationESQL.st_y.markdown": " ### ST_Y Extrait la coordonnée `y` du point fourni. Si les points sont de type `geo_point`, cela revient à extraire la valeur de la `latitude`. ``` ROW point = TO_GEOPOINT(\"POINT(42.97109629958868 14.7552534006536)\") | EVAL x = ST_X(point), y = ST_Y(point) ```", "languageDocumentation.documentationESQL.starts_with": "STARTS_WITH", - "languageDocumentation.documentationESQL.starts_with.markdown": "\n\n ### STARTS_WITH\n Renvoie un booléen qui indique si une chaîne de mot-clés débute par une autre chaîne.\n\n ````\n FROM employees\n | KEEP last_name\n | EVAL ln_S = STARTS_WITH(last_name, \"B\")\n ````\n ", + "languageDocumentation.documentationESQL.starts_with.markdown": " ### STARTS_WITH Renvoie une valeur booléenne qui indique si une chaîne de mots-clés débute par une autre chaîne. ``` FROM employees | KEEP last_name | EVAL ln_S = STARTS_WITH(last_name, \"B\") ```", "languageDocumentation.documentationESQL.statsby": "STATS ... BY", - "languageDocumentation.documentationESQL.statsby.markdown": "### STATS ... BY\nUtilisez `STATS ... BY` pour regrouper les lignes en fonction d'une valeur commune et calculer une ou plusieurs valeurs agrégées sur les lignes regroupées.\n\n**Exemples** :\n\n````\nFROM employees\n| STATS count = COUNT(emp_no) BY languages\n| SORT languages\n````\n\nSi `BY` est omis, le tableau de sortie contient exactement une ligne avec les agrégations appliquées sur l'ensemble des données :\n\n````\nFROM employees\n| STATS avg_lang = AVG(languages)\n````\n\nIl est possible de calculer plusieurs valeurs :\n\n````\nFROM employees\n| STATS avg_lang = AVG(languages), max_lang = MAX(languages)\n````\n\nIl est également possible d'effectuer des regroupements en fonction de plusieurs valeurs (uniquement pour les champs longs et les champs de la famille de mots-clés) :\n\n````\nFROM employees\n| EVAL hired = DATE_FORMAT(hire_date, \"YYYY\")\n| STATS avg_salary = AVG(salary) BY hired, languages.long\n| EVAL avg_salary = ROUND(avg_salary)\n| SORT hired, languages.long\n````\n\nConsultez la rubrique **Fonctions d'agrégation** pour obtenir la liste des fonctions pouvant être utilisées avec `STATS ... BY`.\n\nLes fonctions d'agrégation et les expressions de regroupement acceptent toutes deux d'autres fonctions. Ceci est utile pour utiliser `STATS...BY` sur des colonnes à valeur multiple. Par exemple, pour calculer l'évolution moyenne du salaire, vous pouvez utiliser `MV_AVG` pour faire la moyenne des multiples valeurs par employé, et utiliser le résultat avec la fonction `AVG` :\n\n````\nFROM employees\n| STATS avg_salary_change = AVG(MV_AVG(salary_change))\n````\n\nLe regroupement par expression est par exemple le regroupement des employés en fonction de la première lettre de leur nom de famille :\n\n````\nFROM employees\n| STATS my_count = COUNT() BY LEFT(last_name, 1)\n| SORT \"LEFT(last_name, 1)\"\n````\n\nIl n'est pas obligatoire d'indiquer le nom de la colonne de sortie. S'il n'est pas spécifié, le nouveau nom de la colonne est égal à l'expression. La requête suivante renvoie une colonne appelée `AVG(salary)` :\n\n````\nFROM employees\n| STATS AVG(salary)\n````\n\nComme ce nom contient des caractères spéciaux, il doit être placé entre deux caractères (`) lorsqu'il est utilisé dans des commandes suivantes :\n\n````\nFROM employees\n| STATS AVG(salary)\n| EVAL avg_salary_rounded = ROUND(\"AVG(salary)\")\n````\n\n**Remarque** : `STATS` sans aucun groupe est beaucoup plus rapide que l'ajout d'un groupe.\n\n**Remarque** : Le regroupement sur une seule expression est actuellement beaucoup plus optimisé que le regroupement sur plusieurs expressions.\n ", + "languageDocumentation.documentationESQL.statsby.markdown": "### STATS ... BY Utilisez `STATS ... BY` pour regrouper les lignes en fonction d'une valeur commune et calculer une ou plusieurs valeurs agrégées sur les lignes regroupées. **Exemples** : ``` FROM employees | STATS count = COUNT(emp_no) BY languages | SORT languages ``` Si `BY` est omis, le tableau de sortie contient exactement une ligne avec les agrégations appliquées sur l'ensemble des données : ``` FROM employees | STATS avg_lang = AVG(languages) ``` Il est possible de calculer plusieurs valeurs : ``` FROM employees | STATS avg_lang = AVG(languages), max_lang = MAX(languages) ``` Il est également possible d'effectuer des regroupements en fonction de plusieurs valeurs (uniquement pour les champs longs et les champs de la famille de mots-clés) : ``` FROM employees | EVAL hired = DATE_FORMAT(hire_date, \"YYYY\") | STATS avg_salary = AVG(salary) BY hired, languages.long | EVAL avg_salary = ROUND(avg_salary) | SORT hired, languages.long ``` Consultez la rubrique **Fonctions d'agrégation** pour obtenir la liste des fonctions pouvant être utilisées avec `STATS ... BY`. Les fonctions d'agrégation et les expressions de regroupement acceptent toutes deux d'autres fonctions. Ceci est utile pour utiliser `STATS...BY` sur des colonnes à valeur multiple. Par exemple, pour calculer l'évolution moyenne du salaire, vous pouvez utiliser `MV_AVG` pour faire la moyenne des multiples valeurs par employé, et utiliser le résultat avec la fonction `AVG` : ``` FROM employees | STATS avg_salary_change = AVG(MV_AVG(salary_change)) ``` Le regroupement par expression est par exemple le regroupement des employés en fonction de la première lettre de leur nom de famille : ``` FROM employees | STATS my_count = COUNT() BY LEFT(last_name, 1) | SORT `LEFT(last_name, 1)` ``` Il n'est pas obligatoire d'indiquer le nom de la colonne de sortie. S'il n'est pas spécifié, le nouveau nom de la colonne est égal à l'expression. La requête suivante renvoie une colonne appelée `AVG(salary)` : ``` FROM employees | STATS AVG(salary) ``` Comme ce nom contient des caractères spéciaux, il doit être placé entre deux caractères (`) lorsqu'il est utilisé dans les commandes suivantes : ``` FROM employees | STATS AVG(salary) | EVAL avg_salary_rounded = ROUND(`AVG(salary)`) ``` **Remarque** : `STATS` sans aucun groupe est beaucoup plus rapide que l'ajout d'un groupe. **Remarque** : Le regroupement sur une seule expression est actuellement beaucoup plus optimisé que le regroupement sur plusieurs expressions.", "languageDocumentation.documentationESQL.stringOperators": "LIKE et RLIKE", - "languageDocumentation.documentationESQL.stringOperators.markdown": "### LIKE et RLIKE\nPour comparer des chaînes en utilisant des caractères génériques ou des expressions régulières, utilisez `LIKE` ou `RLIKE` :\n\nUtilisez `LIKE` pour faire correspondre des chaînes à l'aide de caractères génériques. Les caractères génériques suivants sont pris en charge :\n\n* `*` correspond à zéro caractère ou plus.\n* `?` correspond à un seul caractère.\n\n````\nFROM employees\n| WHERE first_name LIKE \"?b*\"\n| KEEP first_name, last_name\n````\n\nUtilisez `RLIKE` pour faire correspondre des chaînes à l'aide d'expressions régulières :\n\n````\nFROM employees\n| WHERE first_name RLIKE \".leja.*\"\n| KEEP first_name, last_name\n````\n ", + "languageDocumentation.documentationESQL.stringOperators.markdown": "### LIKE et RLIKE Pour comparer des chaînes en utilisant des caractères génériques ou des expressions régulières, utilisez `LIKE` ou `RLIKE` : Utilisez `LIKE` pour faire correspondre des chaînes à l'aide de caractères génériques. Les caractères génériques suivants sont pris en charge : * `*` correspond à zéro ou plusieurs caractères. * `?` correspond à un seul caractère. ``` FROM employees | WHERE first_name LIKE \"?b*\" | KEEP first_name, last_name ``` Utilisez `RLIKE` pour faire correspondre des chaînes à l'aide d'expressions régulières : ``` FROM employees | WHERE first_name RLIKE \".leja.*\" | KEEP first_name, last_name ```", "languageDocumentation.documentationESQL.substring": "SUBSTRING", - "languageDocumentation.documentationESQL.substring.markdown": "\n\n ### SUBSTRING\n Renvoie la sous-chaîne d'une chaîne, délimitée en fonction d'une position de départ et d'une longueur facultative\n\n ````\n FROM employees\n | KEEP last_name\n | EVAL ln_sub = SUBSTRING(last_name, 1, 3)\n ````\n ", + "languageDocumentation.documentationESQL.substring.markdown": " ### SUBSTRING Renvoie la sous-chaîne d'une chaîne, délimitée en fonction d'une position de départ et d'une longueur facultative. ``` FROM employees | KEEP last_name | EVAL ln_sub = SUBSTRING(last_name, 1, 3) ```", + "languageDocumentation.documentationESQL.sum": "SUM", + "languageDocumentation.documentationESQL.sum.markdown": " ### SUM La somme d'une expression numérique. ``` FROM employees | STATS SUM(languages) ```", "languageDocumentation.documentationESQL.tan": "TAN", - "languageDocumentation.documentationESQL.tan.markdown": "\n\n ### TAN\n Renvoie la fonction trigonométrique Tangente d'un angle.\n\n ````\n ROW a=1.8 \n | EVAL tan=TAN(a)\n ````\n ", + "languageDocumentation.documentationESQL.tan.markdown": " ### TAN Renvoie la tangente d'un angle. ``` ROW a=1.8 | EVAL tan=TAN(a) ```", "languageDocumentation.documentationESQL.tanh": "TANH", - "languageDocumentation.documentationESQL.tanh.markdown": "\n\n ### TANH\n Renvoie la fonction hyperbolique Tangente d'un angle.\n\n ````\n ROW a=1.8 \n | EVAL tanh=TANH(a)\n ````\n ", + "languageDocumentation.documentationESQL.tanh.markdown": " ### TANH Renvoie la tangente hyperbolique d'un nombre. ``` ROW a=1.8 | EVAL tanh=TANH(a) ```", "languageDocumentation.documentationESQL.tau": "TAU", - "languageDocumentation.documentationESQL.tau.markdown": "\n\n ### TAU\n Renvoie le rapport entre la circonférence et le rayon d'un cercle.\n\n ````\n ROW TAU()\n ````\n ", + "languageDocumentation.documentationESQL.tau.markdown": " ### TAU Renvoie le rapport entre la circonférence et le rayon d'un cercle. ``` ROW TAU() ```", "languageDocumentation.documentationESQL.to_base64": "TO_BASE64", - "languageDocumentation.documentationESQL.to_base64.markdown": "\n\n ### TO_BASE64\n Encode une chaîne en chaîne base64.\n\n ````\n row a = \"elastic\" \n | eval e = to_base64(a)\n ````\n ", + "languageDocumentation.documentationESQL.to_base64.markdown": " ### TO_BASE64 Encode une chaîne en chaîne base64. ``` row a = \"elastic\" | eval e = to_base64(a) ```", "languageDocumentation.documentationESQL.to_boolean": "TO_BOOLEAN", - "languageDocumentation.documentationESQL.to_boolean.markdown": "\n\n ### TO_BOOLEAN\n Convertit une valeur d'entrée en une valeur booléenne.\n Une chaîne de valeur *true* sera convertie, sans tenir compte de la casse, en une valeur booléenne *true*.\n Pour toute autre valeur, y compris une chaîne vide, la fonction renverra *false*.\n La valeur numérique *0* sera convertie en *false*, toute autre valeur sera convertie en *true*.\n\n ````\n ROW str = [\"true\", \"TRuE\", \"false\", \"\", \"yes\", \"1\"]\n | EVAL bool = TO_BOOLEAN(str)\n ````\n ", + "languageDocumentation.documentationESQL.to_boolean.markdown": " ### TO_BOOLEAN Convertit une valeur d'entrée en une valeur booléenne. Une chaîne de valeur *true* sera convertie, sans tenir compte de la casse, en une valeur booléenne *true*. Pour toute autre valeur, y compris une chaîne vide, la fonction renverra *false*. La valeur numérique *0* sera convertie en *false*, toute autre valeur sera convertie en *true*. ``` ROW str = [\"true\", \"TRuE\", \"false\", \"\", \"yes\", \"1\"] | EVAL bool = TO_BOOLEAN(str) ```", "languageDocumentation.documentationESQL.to_cartesianpoint": "TO_CARTESIANPOINT", - "languageDocumentation.documentationESQL.to_cartesianpoint.markdown": "\n\n ### TO_CARTESIANPOINT\n Convertit la valeur d'une entrée en une valeur `cartesian_point`.\n Une chaîne ne sera convertie que si elle respecte le format WKT Point.\n\n ````\n ROW wkt = [\"POINT(4297.11 -1475.53)\", \"POINT(7580.93 2272.77)\"]\n | MV_EXPAND wkt\n | EVAL pt = TO_CARTESIANPOINT(wkt)\n ````\n ", + "languageDocumentation.documentationESQL.to_cartesianpoint.markdown": " ### TO_CARTESIANPOINT Convertit la valeur d'une entrée en une valeur `cartesian_point`. Une chaîne ne sera convertie que si elle respecte le format WKT Point. ``` ROW wkt = [\"POINT(4297.11 -1475.53)\", \"POINT(7580.93 2272.77)\"] | MV_EXPAND wkt | EVAL pt = TO_CARTESIANPOINT(wkt) ```", "languageDocumentation.documentationESQL.to_cartesianshape": "TO_CARTESIANSHAPE", - "languageDocumentation.documentationESQL.to_cartesianshape.markdown": "\n\n ### TO_CARTESIANSHAPE\n Convertit une valeur d'entrée en une valeur `cartesian_shape`.\n Une chaîne ne sera convertie que si elle respecte le format WKT.\n\n ````\n ROW wkt = [\"POINT(4297.11 -1475.53)\", \"POLYGON ((3339584.72 1118889.97, 4452779.63 4865942.27, 2226389.81 4865942.27, 1113194.90 2273030.92, 3339584.72 1118889.97))\"]\n | MV_EXPAND wkt\n | EVAL geom = TO_CARTESIANSHAPE(wkt)\n ````\n ", + "languageDocumentation.documentationESQL.to_cartesianshape.markdown": " ### TO_CARTESIANSHAPE Convertit une valeur d'entrée en une valeur `cartesian_shape`. Une chaîne ne sera convertie que si elle respecte le format WKT. ``` ROW wkt = [\"POINT(4297.11 -1475.53)\", \"POLYGON ((3339584.72 1118889.97, 4452779.63 4865942.27, 2226389.81 4865942.27, 1113194.90 2273030.92, 3339584.72 1118889.97))\"] | MV_EXPAND wkt | EVAL geom = TO_CARTESIANSHAPE(wkt) ```", + "languageDocumentation.documentationESQL.to_date_nanos": "TO_DATE_NANOS", + "languageDocumentation.documentationESQL.to_date_nanos.markdown": " ### TO_DATE_NANOS Convertit une entrée en une valeur de date de résolution nanoseconde (ou date_nanos). Remarque : La plage de \"date nanos\" est comprise entre 1970-01-01T00:00:00.000000000Z et 2262-04-11T23:47:16.854775807Z. En outre, les nombres entiers ne peuvent pas être convertis en \"date nanos\", car la plage des nanosecondes en nombres entiers ne couvre qu'environ 2 secondes après l'heure.", + "languageDocumentation.documentationESQL.to_dateperiod": "TO_DATEPERIOD", + "languageDocumentation.documentationESQL.to_dateperiod.markdown": " ### TO_DATEPERIOD Convertit une valeur d'entrée en une valeur `date_period`. ``` row x = \"2024-01-01\"::datetime | eval y = x + \"3 DAYS\"::date_period, z = x - to_dateperiod(\"3 days\"); ```", "languageDocumentation.documentationESQL.to_datetime": "TO_DATETIME", - "languageDocumentation.documentationESQL.to_datetime.markdown": "\n\n ### TO_DATETIME\n Convertit une valeur d'entrée en une valeur de date.\n Une chaîne ne sera convertie que si elle respecte le format `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'`.\n Pour convertir des dates vers d'autres formats, utilisez `DATE_PARSE`.\n\n ````\n ROW string = [\"1953-09-02T00:00:00.000Z\", \"1964-06-02T00:00:00.000Z\", \"1964-06-02 00:00:00\"]\n | EVAL datetime = TO_DATETIME(string)\n ````\n ", + "languageDocumentation.documentationESQL.to_datetime.markdown": " ### TO_DATETIME Convertit une valeur d'entrée en une valeur de date. Une chaîne ne sera convertie que si elle respecte le format `yyyy-MM-dd'T'HH:mm:ss.SSS'Z'`. Pour convertir des dates vers d'autres formats, utilisez `DATE_PARSE`. ``` ROW string = [\"1953-09-02T00:00:00.000Z\", \"1964-06-02T00:00:00.000Z\", \"1964-06-02 00:00:00\"] | EVAL datetime = TO_DATETIME(string) ``` Remarque : Notez que lors de la conversion de la résolution en nanosecondes à la résolution en millisecondes avec cette fonction, la date en nanosecondes est tronquée et non arrondie.", "languageDocumentation.documentationESQL.to_degrees": "TO_DEGREES", - "languageDocumentation.documentationESQL.to_degrees.markdown": "\n\n ### TO_DEGREES\n Convertit un nombre en radians en degrés.\n\n ````\n ROW rad = [1.57, 3.14, 4.71]\n | EVAL deg = TO_DEGREES(rad)\n ````\n ", + "languageDocumentation.documentationESQL.to_degrees.markdown": " ### TO_DEGREES Convertit un nombre en radians en degrés. ``` ROW rad = [1.57, 3.14, 4.71] | EVAL deg = TO_DEGREES(rad) ```", "languageDocumentation.documentationESQL.to_double": "TO_DOUBLE", - "languageDocumentation.documentationESQL.to_double.markdown": "\n\n ### TO_DOUBLE\n Convertit une valeur d'entrée en une valeur double. Si le paramètre d'entrée est de type date,\n sa valeur sera interprétée en millisecondes depuis l'heure Unix,\n convertie en double. Le booléen *true* sera converti en double *1.0*, et *false* en *0.0*.\n\n ````\n ROW str1 = \"5.20128E11\", str2 = \"foo\"\n | EVAL dbl = TO_DOUBLE(\"520128000000\"), dbl1 = TO_DOUBLE(str1), dbl2 = TO_DOUBLE(str2)\n ````\n ", + "languageDocumentation.documentationESQL.to_double.markdown": " ### TO_DOUBLE Convertit une valeur d'entrée en une valeur double. Si le paramètre d'entrée est de type date, sa valeur sera interprétée en millisecondes depuis l'heure Unix, convertie en double. Le booléen *true* sera converti en double *1.0*, et *false* en *0.0*. ``` ROW str1 = \"5.20128E11\", str2 = \"foo\" | EVAL dbl = TO_DOUBLE(\"520128000000\"), dbl1 = TO_DOUBLE(str1), dbl2 = TO_DOUBLE(str2) ```", "languageDocumentation.documentationESQL.to_geopoint": "TO_GEOPOINT", - "languageDocumentation.documentationESQL.to_geopoint.markdown": "\n\n ### TO_GEOPOINT\n Convertit une valeur d'entrée en une valeur `geo_point`.\n Une chaîne ne sera convertie que si elle respecte le format WKT Point.\n\n ````\n ROW wkt = \"POINT(42.97109630194 14.7552534413725)\"\n | EVAL pt = TO_GEOPOINT(wkt)\n ````\n ", + "languageDocumentation.documentationESQL.to_geopoint.markdown": " ### TO_GEOPOINT Convertit une valeur d'entrée en une valeur `geo_point`. Une chaîne ne sera convertie que si elle respecte le format WKT Point. ``` ROW wkt = \"POINT(42.97109630194 14.7552534413725)\" | EVAL pt = TO_GEOPOINT(wkt) ```", "languageDocumentation.documentationESQL.to_geoshape": "TO_GEOSHAPE", - "languageDocumentation.documentationESQL.to_geoshape.markdown": "\n\n ### TO_GEOSHAPE\n Convertit une valeur d'entrée en une valeur `geo_shape`.\n Une chaîne ne sera convertie que si elle respecte le format WKT.\n\n ````\n ROW wkt = \"POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))\"\n | EVAL geom = TO_GEOSHAPE(wkt)\n ````\n ", + "languageDocumentation.documentationESQL.to_geoshape.markdown": " ### TO_GEOSHAPE Convertit une valeur d'entrée en une valeur `geo_shape`. Une chaîne ne sera convertie que si elle respecte le format WKT. ``` ROW wkt = \"POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))\" | EVAL geom = TO_GEOSHAPE(wkt) ```", "languageDocumentation.documentationESQL.to_integer": "TO_INTEGER", - "languageDocumentation.documentationESQL.to_integer.markdown": "\n\n ### TO_INTEGER\n Convertit une valeur d'entrée en une valeur entière.\n Si le paramètre d'entrée est de type date, sa valeur sera interprétée en millisecondes\n depuis l'heure Unix, convertie en entier.\n Le booléen *true* sera converti en entier *1*, et *false* en *0*.\n\n ````\n ROW long = [5013792, 2147483647, 501379200000]\n | EVAL int = TO_INTEGER(long)\n ````\n ", + "languageDocumentation.documentationESQL.to_integer.markdown": " ### TO_INTEGER Convertit une valeur d'entrée en une valeur entière. Si le paramètre d'entrée est de type date, sa valeur sera interprétée en millisecondes depuis l'heure Unix, convertie en nombre entier. Le booléen *true* sera converti en entier *1*, et *false* en *0*. ``` ROW long = [5013792, 2147483647, 501379200000] | EVAL int = TO_INTEGER(long) ```", "languageDocumentation.documentationESQL.to_ip": "TO_IP", - "languageDocumentation.documentationESQL.to_ip.markdown": "\n\n ### TO_IP\n Convertit une chaîne d'entrée en valeur IP.\n\n ````\n ROW str1 = \"1.1.1.1\", str2 = \"foo\"\n | EVAL ip1 = TO_IP(str1), ip2 = TO_IP(str2)\n | WHERE CIDR_MATCH(ip1, \"1.0.0.0/8\")\n ````\n ", + "languageDocumentation.documentationESQL.to_ip.markdown": " ### TO_IP Convertit une chaîne d'entrée en valeur IP. ``` ROW str1 = \"1.1.1.1\", str2 = \"foo\" | EVAL ip1 = TO_IP(str1), ip2 = TO_IP(str2) | WHERE CIDR_MATCH(ip1, \"1.0.0.0/8\") ```", "languageDocumentation.documentationESQL.to_long": "TO_LONG", - "languageDocumentation.documentationESQL.to_long.markdown": "\n\n ### TO_LONG\n Convertit une valeur d'entrée en une valeur longue. Si le paramètre d'entrée est de type date,\n sa valeur sera interprétée en millisecondes depuis l'heure Unix, convertie en valeur longue.\n Le booléen *true* sera converti en valeur longue *1*, et *false* en *0*.\n\n ````\n ROW str1 = \"2147483648\", str2 = \"2147483648.2\", str3 = \"foo\"\n | EVAL long1 = TO_LONG(str1), long2 = TO_LONG(str2), long3 = TO_LONG(str3)\n ````\n ", + "languageDocumentation.documentationESQL.to_long.markdown": " ### TO_LONG Convertit une valeur d'entrée en une valeur longue. Si le paramètre d'entrée est de type date, sa valeur sera interprétée en millisecondes depuis l'heure Unix, convertie en valeur longue. Le booléen *true* sera converti en valeur longue *1*, et *false* en *0*. ``` ROW str1 = \"2147483648\", str2 = \"2147483648.2\", str3 = \"foo\" | EVAL long1 = TO_LONG(str1), long2 = TO_LONG(str2), long3 = TO_LONG(str3) ```", "languageDocumentation.documentationESQL.to_lower": "TO_LOWER", - "languageDocumentation.documentationESQL.to_lower.markdown": "\n\n ### TO_LOWER\n Renvoie une nouvelle chaîne représentant la chaîne d'entrée convertie en minuscules.\n\n ````\n ROW message = \"Some Text\"\n | EVAL message_lower = TO_LOWER(message)\n ````\n ", + "languageDocumentation.documentationESQL.to_lower.markdown": " ### TO_LOWER Renvoie une nouvelle chaîne représentant la chaîne d'entrée convertie en minuscules. ``` ROW message = \"Some Text\" | EVAL message_lower = TO_LOWER(message) ```", "languageDocumentation.documentationESQL.to_radians": "TO_RADIANS", - "languageDocumentation.documentationESQL.to_radians.markdown": "\n\n ### TO_RADIANS\n Convertit un nombre en degrés en radians.\n\n ````\n ROW deg = [90.0, 180.0, 270.0]\n | EVAL rad = TO_RADIANS(deg)\n ````\n ", + "languageDocumentation.documentationESQL.to_radians.markdown": " ### TO_RADIANS Convertit un nombre en degrés en radians. ``` ROW deg = [90.0, 180.0, 270.0] | EVAL rad = TO_RADIANS(deg) ```", "languageDocumentation.documentationESQL.to_string": "TO_STRING", - "languageDocumentation.documentationESQL.to_string.markdown": "\n\n ### TO_STRING\n Convertit une valeur d'entrée en une chaîne.\n\n ````\n ROW a=10\n | EVAL j = TO_STRING(a)\n ````\n ", + "languageDocumentation.documentationESQL.to_string.markdown": " ### TO_STRING Convertit une valeur d'entrée en une chaîne. ``` ROW a=10 | EVAL j = TO_STRING(a) ```", + "languageDocumentation.documentationESQL.to_timeduration": "TO_TIMEDURATION", + "languageDocumentation.documentationESQL.to_timeduration.markdown": " ### TO_TIMEDURATION Convertit une valeur d'entrée en valeur `time_duration`. ``` row x = \"2024-01-01\"::datetime | eval y = x + \"3 hours\"::time_duration, z = x - to_timeduration(\"3 hours\"); ```", "languageDocumentation.documentationESQL.to_unsigned_long": "TO_UNSIGNED_LONG", - "languageDocumentation.documentationESQL.to_unsigned_long.markdown": "\n\n ### TO_UNSIGNED_LONG\n Convertit une valeur d'entrée en une valeur longue non signée. Si le paramètre d'entrée est de type date,\n sa valeur sera interprétée en millisecondes depuis l'heure Unix, convertie en valeur longue non signée.\n Le booléen *true* sera converti en valeur longue non signée *1*, et *false* en *0*.\n\n ````\n ROW str1 = \"2147483648\", str2 = \"2147483648.2\", str3 = \"foo\"\n | EVAL long1 = TO_UNSIGNED_LONG(str1), long2 = TO_ULONG(str2), long3 = TO_UL(str3)\n ````\n ", + "languageDocumentation.documentationESQL.to_unsigned_long.markdown": " ### TO_UNSIGNED_LONG Convertit une valeur d'entrée en une valeur longue non signée. Si le paramètre d'entrée est de type date, sa valeur sera interprétée en millisecondes depuis l'heure Unix, convertie en valeur longue non signée. Le booléen *true* sera converti en valeur longue non signée *1*, et *false* en *0*. ``` ROW str1 = \"2147483648\", str2 = \"2147483648.2\", str3 = \"foo\" | EVAL long1 = TO_UNSIGNED_LONG(str1), long2 = TO_ULONG(str2), long3 = TO_UL(str3) ```", "languageDocumentation.documentationESQL.to_upper": "TO_UPPER", - "languageDocumentation.documentationESQL.to_upper.markdown": "\n\n ### TO_UPPER\n Renvoie une nouvelle chaîne représentant la chaîne d'entrée convertie en majuscules.\n\n ````\n ROW message = \"Some Text\"\n | EVAL message_upper = TO_UPPER(message)\n ````\n ", + "languageDocumentation.documentationESQL.to_upper.markdown": " ### TO_UPPER Renvoie une nouvelle chaîne représentant la chaîne d'entrée convertie en majuscules. ``` ROW message = \"Some Text\" | EVAL message_upper = TO_UPPER(message) ```", "languageDocumentation.documentationESQL.to_version": "TO_VERSION", - "languageDocumentation.documentationESQL.to_version.markdown": "\n\n ### TO_VERSION\n Convertit une chaîne d'entrée en une valeur de version.\n\n ````\n ROW v = TO_VERSION(\"1.2.3\")\n ````\n ", + "languageDocumentation.documentationESQL.to_version.markdown": " ### TO_VERSION Convertit une chaîne d'entrée en une valeur de version. ``` ROW v = TO_VERSION(\"1.2.3\") ```", + "languageDocumentation.documentationESQL.top": "TOP", + "languageDocumentation.documentationESQL.top.markdown": " ### TOP Collecte les valeurs les plus élevées d'un champ. Inclut les valeurs répétées. ``` FROM employees | STATS top_salaries = TOP(salary, 3, \"desc\"), top_salary = MAX(salary) ```", "languageDocumentation.documentationESQL.trim": "TRIM", - "languageDocumentation.documentationESQL.trim.markdown": "\n\n ### TRIM\n Supprime les espaces de début et de fin d'une chaîne.\n\n ````\n ROW message = \" some text \", color = \" red \"\n | EVAL message = TRIM(message)\n | EVAL color = TRIM(color)\n ````\n ", + "languageDocumentation.documentationESQL.trim.markdown": " ### TRIM Supprime les espaces de début et de fin d'une chaîne. ``` ROW message = \" some text \", color = \" red \" | EVAL message = TRIM(message) | EVAL color = TRIM(color) ```", + "languageDocumentation.documentationESQL.values": "VALEURS", + "languageDocumentation.documentationESQL.values.markdown": " ### VALUES Renvoie toutes les valeurs d'un groupe dans un champ multivalué. L'ordre des valeurs renvoyées n'est pas garanti. Si vous avez besoin que les valeurs renvoyées soient dans l'ordre, utilisez `esql-mv_sort`. ``` FROM employees | EVAL first_letter = SUBSTRING(first_name, 0, 1) | STATS first_name=MV_SORT(VALUES(first_name)) BY first_letter | SORT first_letter ```", + "languageDocumentation.documentationESQL.weighted_avg": "WEIGHTED_AVG", + "languageDocumentation.documentationESQL.weighted_avg.markdown": " ### WEIGHTED_AVG La moyenne pondérée d'une expression numérique. ``` FROM employees | STATS w_avg = WEIGHTED_AVG(salary, height) by languages | EVAL w_avg = ROUND(w_avg) | KEEP w_avg, languages | SORT languages ```", "languageDocumentation.documentationESQL.where": "WHERE", - "languageDocumentation.documentationESQL.where.markdown": "### WHERE\nUtilisez `WHERE` afin d'obtenir un tableau qui comprend toutes les lignes du tableau d'entrée pour lesquelles la condition fournie est évaluée à `true` :\n \n````\nFROM employees\n| KEEP first_name, last_name, still_hired\n| WHERE still_hired == true\n````\n\n#### Opérateurs\n\nPour obtenir un aperçu des opérateurs pris en charge, consultez la section **Opérateurs**.\n\n#### Fonctions\n`WHERE` prend en charge diverses fonctions de calcul des valeurs. Pour en savoir plus, consultez la section **Fonctions**.\n ", + "languageDocumentation.documentationESQL.where.markdown": "### WHERE Utilisez `WHERE` afin d'obtenir un tableau qui comprend toutes les lignes du tableau d'entrée pour lesquelles la condition fournie est évaluée à `true` : ``` FROM employees | KEEP first_name, last_name, still_hired | WHERE still_hired == true ``` #### Opérateurs Pour obtenir un aperçu des opérateurs pris en charge, consultez la section **Opérateurs**. #### Fonctions `WHERE` prend en charge diverses fonctions de calcul des valeurs. Pour en savoir plus, consultez la section **Fonctions**.", + "languageDocumentation.documentationFlyoutTitle": "Référence rapide ES|QL", "languageDocumentation.documentationLinkLabel": "Voir toute la documentation", + "languageDocumentation.esqlDocsLabel": "Sélectionnez ou recherchez des thèmes", + "languageDocumentation.esqlDocsLinkLabel": "Voir toute la documentation ES|QL", + "languageDocumentation.esqlSections.initialSectionLabel": "ES|QL", "languageDocumentation.header": "Référence de {language}", + "languageDocumentation.navigationAriaLabel": "Naviguer dans la documentation", + "languageDocumentation.navigationPlaceholder": "Commandes et fonctions", "languageDocumentation.searchPlaceholder": "Recherche", "languageDocumentation.tooltip": "Référence de {lang}", "lensFormulaDocs.avg": "Moyenne", "lensFormulaDocs.boolean": "booléen", "lensFormulaDocs.cardinality": "Décompte unique", - "lensFormulaDocs.cardinality.documentation.markdown": "\nCalcule le nombre de valeurs uniques d'un champ donné. Fonctionne pour les nombres, les chaînes, les dates et les valeurs booléennes.\n\nExemple : calculer le nombre de produits différents : \n`unique_count(product.name)`\n\nExemple : calculer le nombre de produits différents du groupe \"clothes\" : \n`unique_count(product.name, kql='product.group=clothes')`\n ", + "lensFormulaDocs.cardinality.documentation.markdown": "Calcule le nombre de valeurs uniques d'un champ donné. Fonctionne pour les nombres, les chaînes, les dates et les valeurs booléennes. Exemple : Calculer le nombre de produits différents : `unique_count(product.name)` Exemple : Calculer le nombre de produits différents du groupe \"vêtements\" : `unique_count(product.name, kql='product.group=clothes')`", "lensFormulaDocs.cardinality.signature": "champ : chaîne", "lensFormulaDocs.CommonFormulaDocumentation": "Les formules les plus courantes divisent deux valeurs pour produire un pourcentage. Pour obtenir un affichage correct, définissez \"Format de valeur\" sur \"pourcent\".", "lensFormulaDocs.count": "Décompte", - "lensFormulaDocs.count.documentation.markdown": "\nNombre total de documents. Lorsque vous fournissez un champ, le nombre total de valeurs de champ est compté. Lorsque vous utilisez la fonction de décompte pour les champs qui comportent plusieurs valeurs dans un même document, toutes les valeurs sont comptées.\n\n#### Exemples\n\nPour calculer le nombre total de documents, utilisez `count()`.\n\nPour calculer le nombre de produits, utilisez `count(products.id)`.\n\nPour calculer le nombre de documents qui correspondent à un filtre donné, utilisez `count(kql='price > 500')`.\n", + "lensFormulaDocs.count.documentation.markdown": "Nombre total de documents. Lorsque vous fournissez un champ, le nombre total de valeurs de champ est compté. Lorsque vous utilisez la fonction de décompte pour les champs qui comportent plusieurs valeurs dans un même document, toutes les valeurs sont comptées. #### Exemples Pour calculer le nombre total de documents, utilisez `count()`. Pour calculer le nombre de produits, utilisez `count(products.id)`. Pour calculer le nombre de documents qui correspondent à un filtre donné, utilisez `count(kql='price > 500')`.", "lensFormulaDocs.count.signature": "[champ : chaîne]", "lensFormulaDocs.counterRate": "Taux de compteur", - "lensFormulaDocs.counterRate.documentation.markdown": "\nCalcule le taux d'un compteur toujours croissant. Cette fonction renvoie uniquement des résultats utiles inhérents aux champs d'indicateurs de compteur qui contiennent une mesure quelconque à croissance régulière.\nSi la valeur diminue, elle est interprétée comme une mesure de réinitialisation de compteur. Pour obtenir des résultats plus précis, `counter_rate\" doit être calculé d’après la valeur `max` du champ.\n\nCe calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures.\nIl utilise l'intervalle en cours utilisé dans la formule.\n\nExemple : visualiser le taux d'octets reçus au fil du temps par un serveur Memcached : \n`counter_rate(max(memcached.stats.read.bytes))`\n ", + "lensFormulaDocs.counterRate.documentation.markdown": "Calcule le taux d'un compteur toujours croissant. Cette fonction renvoie uniquement des résultats utiles inhérents aux champs d'indicateurs de compteur qui contiennent une mesure quelconque à croissance régulière. Si la valeur diminue, elle est interprétée comme une mesure de réinitialisation de compteur. Pour obtenir des résultats plus précis, `counter_rate\" doit être calculé d’après la valeur `max` du champ. Ce calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures. Il utilise l'intervalle en cours utilisé dans la formule. Exemple : Visualiser le taux d'octets reçus au fil du temps par un serveur Memcached : `counter_rate(max(memcached.stats.read.bytes))`", "lensFormulaDocs.counterRate.signature": "indicateur : nombre", "lensFormulaDocs.cumulative_sum.signature": "indicateur : nombre", "lensFormulaDocs.cumulativeSum": "Somme cumulée", - "lensFormulaDocs.cumulativeSum.documentation.markdown": "\nCalcule la somme cumulée d'un indicateur au fil du temps, en ajoutant toutes les valeurs précédentes d'une série à chaque valeur. Pour utiliser cette fonction, vous devez également configurer une dimension de l'histogramme de dates.\n\nCe calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures.\n\nExemple : visualiser les octets reçus cumulés au fil du temps : \n`cumulative_sum(sum(bytes))`\n", + "lensFormulaDocs.cumulativeSum.documentation.markdown": "Calcule la somme cumulée d'un indicateur au fil du temps, en ajoutant toutes les valeurs précédentes d'une série à chaque valeur. Pour utiliser cette fonction, vous devez également configurer une dimension de l'histogramme de dates. Ce calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures. Exemple : Visualiser les octets reçus cumulés au fil du temps : `cumulative_sum(sum(bytes))`", "lensFormulaDocs.derivative": "Différences", - "lensFormulaDocs.differences.documentation.markdown": "\nCalcule la différence par rapport à la dernière valeur d'un indicateur au fil du temps. Pour utiliser cette fonction, vous devez également configurer une dimension de l'histogramme de dates.\nLes données doivent être séquentielles pour les différences. Si vos données sont vides lorsque vous utilisez des différences, essayez d'augmenter l'intervalle de l'histogramme de dates.\n\nCe calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures.\n\nExemple : visualiser la modification des octets reçus au fil du temps : \n`differences(sum(bytes))`\n", + "lensFormulaDocs.differences.documentation.markdown": "Calcule la différence par rapport à la dernière valeur d'un indicateur au fil du temps. Pour utiliser cette fonction, vous devez également configurer une dimension de l'histogramme de dates. Les données doivent être séquentielles pour les différences. Si vos données sont vides lorsque vous utilisez des différences, essayez d'augmenter l'intervalle de l'histogramme de dates. Ce calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures. Exemple : Visualiser l'évolution du nombre d'octets reçus au fil du temps : `differences(sum(bytes))`", "lensFormulaDocs.differences.signature": "indicateur : nombre", "lensFormulaDocs.documentation.columnCalculationSection": "Calculs de colonnes", "lensFormulaDocs.documentation.columnCalculationSectionDescription": "Ces fonctions sont exécutées pour chaque ligne, mais elles sont fournies avec la colonne entière comme contexte. Elles sont également appelées fonctions de fenêtre.", @@ -5689,92 +6296,92 @@ "lensFormulaDocs.documentation.elasticsearchSection": "Elasticsearch", "lensFormulaDocs.documentation.elasticsearchSectionDescription": "Ces fonctions seront exécutées sur les documents bruts pour chaque ligne du tableau résultant, en agrégeant tous les documents correspondant aux dimensions de répartition en une seule valeur.", "lensFormulaDocs.documentation.filterRatio": "Rapport de filtre", - "lensFormulaDocs.documentation.filterRatioDescription.markdown": "### Rapport de filtre :\n\nUtilisez `kql=''` pour filtrer un ensemble de documents et le comparer à d'autres documents du même regroupement.\nPar exemple, pour consulter l'évolution du taux d'erreur au fil du temps :\n\n````\ncount(kql='response.status_code > 400') / count()\n````\n ", - "lensFormulaDocs.documentation.markdown": "## Fonctionnement\n\nLes formules Lens permettent de réaliser des calculs à l'aide d'une combinaison d'agrégations Elasticsearch et\nde fonctions mathématiques. Trois types principaux de fonctions existent :\n\n* Indicateurs Elasticsearch, comme `sum(bytes)`\n* Fonctions de séries temporelles utilisant les indicateurs Elasticsearch en tant qu'entrée, comme `cumulative_sum()`\n* Fonctions mathématiques, comme `round()`\n\nVoici un exemple de formule qui les utilise tous :\n\n````\nround(100 * moving_average(\naverage(cpu.load.pct),\nwindow=10,\nkql='datacenter.name: east*'\n))\n````\n\nLes fonctions Elasticsearch utilisent un nom de champ, qui peut être entre guillemets. `sum(bytes)` est ainsi identique à\n`sum('bytes')`.\n\nCertaines fonctions utilisent des arguments nommés, comme `moving_average(count(), window=5)`.\n\nLes indicateurs Elasticsearch peuvent être filtrés à l’aide de la syntaxe KQL ou Lucene. Pour ajouter un filtre, utilisez le paramètre\nnommé `kql='field: value'` ou `lucene=''`. Utilisez toujours des guillemets simples pour écrire des requêtes KQL\nou Lucene. Si votre recherche contient un guillemet simple, utilisez une barre oblique inverse pour l’échapper, par exemple : `kql='Women\\'s\".\n\nLes fonctions mathématiques peuvent utiliser des arguments positionnels : par exemple, pow(count(), 3) est identique à count() * count() * count().\n\nUtilisez les opérateurs +, -, / et * pour réaliser des opérations de base.\n", + "lensFormulaDocs.documentation.filterRatioDescription.markdown": "### Rapport de filtre : Utilisez `kql=''` pour filtrer un ensemble de documents et le comparer à d'autres documents du même regroupement. Par exemple, pour consulter l'évolution du taux d'erreur au fil du temps : ``` count(kql='response.status_code > 400') / count() ```", + "lensFormulaDocs.documentation.markdown": "## Fonctionnement Les formules Lens permettent de réaliser des calculs à l'aide d'une combinaison d'agrégations Elasticsearch et de fonctions mathématiques. Il existe trois principaux types de fonctions : * Indicateurs Elasticsearch, comme `sum(bytes)` * Fonctions de séries temporelles utilisant les indicateurs Elasticsearch en tant qu'entrée, comme `cumulative_sum()` * Fonctions mathématiques, comme `round()` Voici un exemple de formule qui les utilise tous : ``` round(100 * moving_average( average(cpu.load.pct), window=10, kql='datacenter.name: east*' )) ``` Les fonctions Elasticsearch utilisent un nom de champ, qui peut être entre guillemets. `sum(bytes)` est ainsi identique à `sum('bytes')`. Certaines fonctions utilisent des arguments nommés, comme `moving_average(count(), window=5)`. Les indicateurs Elasticsearch peuvent être filtrés à l’aide de la syntaxe KQL ou Lucene. Pour ajouter un filtre, utilisez le paramètre `kql='field: value'` ou `lucene=''`. Utilisez toujours des guillemets simples pour écrire des requêtes KQL ou Lucene. Si votre recherche contient un guillemet simple, utilisez une barre oblique inverse pour l'échapper, par exemple : `kql='Women\\'s\". Les fonctions mathématiques peuvent utiliser des arguments positionnels : par exemple, pow(count(), 3) est identique à count() * count() * count(). Utilisez les opérateurs +, -, / et * pour réaliser des opérations de base.", "lensFormulaDocs.documentation.mathSection": "Mathématique", "lensFormulaDocs.documentation.mathSectionDescription": "Ces fonctions seront exécutées pour chaque ligne du tableau résultant en utilisant des valeurs uniques de la même ligne calculées à l'aide d'autres fonctions.", "lensFormulaDocs.documentation.percentOfTotal": "Pourcentage du total", - "lensFormulaDocs.documentation.percentOfTotalDescription.markdown": "### Pourcentage du total\n\nLes formules peuvent calculer `overall_sum` pour tous les regroupements,\nce qui permet de convertir chaque regroupement en un pourcentage du total :\n\n````\nsum(products.base_price) / overall_sum(sum(products.base_price))\n````\n ", + "lensFormulaDocs.documentation.percentOfTotalDescription.markdown": "### Pourcentage du total Les formules peuvent calculer `overall_sum` pour tous les regroupements, ce qui permet de convertir chaque regroupement en un pourcentage du total : ``` sum(products.base_price) / overall_sum(sum(products.base_price)) ```", "lensFormulaDocs.documentation.recentChange": "Modification récente", - "lensFormulaDocs.documentation.recentChangeDescription.markdown": "### Modification récente\n\nUtilisez `reducedTimeRange='30m'` pour ajouter un filtre supplémentaire sur la plage temporelle d'un indicateur aligné avec la fin d'une plage temporelle globale. Vous pouvez l'utiliser pour calculer le degré de modification récente d'une valeur.\n\n````\nmax(system.network.in.bytes, reducedTimeRange=\"30m\")\n- min(system.network.in.bytes, reducedTimeRange=\"30m\")\n````\n ", + "lensFormulaDocs.documentation.recentChangeDescription.markdown": "### Modification récente Utilisez `reducedTimeRange='30m'` pour ajouter un filtre supplémentaire sur la plage temporelle d'un indicateur aligné avec la fin d'une plage temporelle globale. Vous pouvez l'utiliser pour calculer le degré de modification récente d'une valeur. ``` max(system.network.in.bytes, reducedTimeRange=\"30m\") - min(system.network.in.bytes, reducedTimeRange=\"30m\") ```", "lensFormulaDocs.documentation.weekOverWeek": "Semaine après semaine", - "lensFormulaDocs.documentation.weekOverWeekDescription.markdown": "### Semaine après semaine :\n\nUtilisez `shift='1w'` pour obtenir la valeur de chaque regroupement\nde la semaine précédente. Le décalage ne doit pas être utilisé avec la fonction *Valeurs les plus élevées*.\n\n````\npercentile(system.network.in.bytes, percentile=99) /\npercentile(system.network.in.bytes, percentile=99, shift='1w')\n````\n ", + "lensFormulaDocs.documentation.weekOverWeekDescription.markdown": "### Semaine après semaine : Utilisez `shift='1w'` pour obtenir la valeur de chaque regroupement de la semaine précédente. Le décalage ne doit pas être utilisé avec la fonction *Valeurs les plus élevées*. ``` percentile(system.network.in.bytes, percentile=99) / percentile(system.network.in.bytes, percentile=99, shift='1w') ```", "lensFormulaDocs.frequentlyUsedHeading": "Formules courantes", "lensFormulaDocs.interval": "Intervalle de l'histogramme des dates", - "lensFormulaDocs.interval.help": "\nL’intervalle minimum spécifié pour l’histogramme de date, en millisecondes (ms).\n\nExemple : Normalisez l'indicateur de façon dynamique en fonction de la taille d'intervalle du compartiment : \n\"sum(bytes) / interval()\"\n", + "lensFormulaDocs.interval.help": "L’intervalle minimum spécifié pour l’histogramme de date, en millisecondes (ms). Exemple : Normalisez l'indicateur de façon dynamique en fonction de la taille d'intervalle du compartiment : `sum(bytes) / interval()`", "lensFormulaDocs.lastValue": "Dernière valeur", - "lensFormulaDocs.lastValue.documentation.markdown": "\nRenvoie la valeur d'un champ du dernier document, triée par le champ d'heure par défaut de la vue de données.\n\nCette fonction permet de récupérer le dernier état d'une entité.\n\nExemple : obtenir le statut actuel du serveur A : \n`last_value(server.status, kql='server.name=\"A\"')`\n", + "lensFormulaDocs.lastValue.documentation.markdown": "Renvoie la valeur d'un champ du dernier document, triée par le champ d'heure par défaut de la vue de données. Cette fonction permet de récupérer le dernier état d'une entité. Exemple : Obtenir le statut actuel du serveur A : `last_value(server.status, kql='server.name=\"A\"')`", "lensFormulaDocs.lastValue.signature": "champ : chaîne", "lensFormulaDocs.max": "Maximum", "lensFormulaDocs.median": "Médiane", - "lensFormulaDocs.metric.documentation.markdown": "\nRenvoie l'indicateur {metric} d'un champ. Cette fonction fonctionne uniquement pour les champs numériques.\n\nExemple : obtenir l'indicateur {metric} d'un prix : \n`{metric}(price)`\n\nExemple : obtenir l'indicateur {metric} d'un prix pour des commandes du Royaume-Uni : \n`{metric}(price, kql='location:UK')`\n ", + "lensFormulaDocs.metric.documentation.markdown": "Renvoie l'indicateur {metric} d'un champ. Cette fonction fonctionne uniquement pour les champs numériques. Exemple : Obtenir l'indicateur {metric} de prix : `{metric}(price)` Exemple : Obtenir l'indicateur {metric} de prix pour les commandes en provenance du Royaume-Uni : `{metric}(price, kql='location:UK')`", "lensFormulaDocs.metric.signature": "champ : chaîne", "lensFormulaDocs.min": "Minimum", "lensFormulaDocs.moving_average.signature": "indicateur : nombre, [window] : nombre", "lensFormulaDocs.movingAverage": "Moyenne mobile", - "lensFormulaDocs.movingAverage.documentation.markdown": "\nCalcule la moyenne mobile d'un indicateur au fil du temps, en prenant la moyenne des n dernières valeurs pour calculer la valeur actuelle. Pour utiliser cette fonction, vous devez également configurer une dimension de l'histogramme de dates.\nLa valeur de fenêtre par défaut est {defaultValue}.\n\nCe calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures.\n\nPrend un paramètre nommé `window` qui spécifie le nombre de dernières valeurs à inclure dans le calcul de la moyenne de la valeur actuelle.\n\nExemple : lisser une ligne de mesures : \n`moving_average(sum(bytes), window=5)`\n", + "lensFormulaDocs.movingAverage.documentation.markdown": "Calcule la moyenne mobile d'un indicateur au fil du temps, en prenant la moyenne des n dernières valeurs pour calculer la valeur actuelle. Pour utiliser cette fonction, vous devez également configurer une dimension de l'histogramme de dates. La valeur de fenêtre par défaut est {defaultValue}. Ce calcul est réalisé séparément pour des séries distinctes définies par des filtres ou des dimensions de valeurs supérieures. Prend un paramètre nommé `window` qui spécifie le nombre de dernières valeurs à inclure dans le calcul de la moyenne de la valeur actuelle. Exemple : Lisser une ligne de mesures : `moving_average(sum(bytes), window=5)`", "lensFormulaDocs.now": "Actuel", - "lensFormulaDocs.now.help": "\nLa durée actuelle passée dans Kibana exprimée en millisecondes (ms).\n\nExemple : Depuis combien de temps (en millisecondes) le serveur est-il en marche depuis son dernier redémarrage ? \n\"now() - last_value(start_time)\"\n", + "lensFormulaDocs.now.help": "La durée actuelle passée dans Kibana exprimée en millisecondes (ms). Exemple : Depuis combien de temps (en millisecondes) le serveur est-il en marche depuis son dernier redémarrage ? `now() - last_value(start_time)`", "lensFormulaDocs.number": "numéro", - "lensFormulaDocs.overall_average.documentation.markdown": "\nCalcule la moyenne d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle.\nD'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes.\n\nSi le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, `overall_average` calcule la moyenne pour toutes les dimensions, quelle que soit la fonction utilisée.\n\nExemple : écart par rapport à la moyenne : \n`sum(bytes) - overall_average(sum(bytes))`\n", - "lensFormulaDocs.overall_max.documentation.markdown": "\nCalcule la valeur maximale d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle.\nD'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes.\n\nSi le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, `overall_max` calcule la valeur maximale pour toutes les dimensions, quelle que soit la fonction utilisée.\n\nExemple : Pourcentage de plage : \n`(sum(bytes) - overall_min(sum(bytes))) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))`\n", + "lensFormulaDocs.overall_average.documentation.markdown": "Calcule la moyenne d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle. D'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes. Si le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, `overall_average` calcule la moyenne pour toutes les dimensions, quelle que soit la fonction utilisée. Exemple : Écart par rapport à la moyenne : `sum(bytes) - overall_average(sum(bytes))`", + "lensFormulaDocs.overall_max.documentation.markdown": "Calcule la valeur maximale d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle. D'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes. Si le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, `overall_max` calcule la valeur maximale pour toutes les dimensions, quelle que soit la fonction utilisée. Exemple : Pourcentage de plage : `(sum(bytes) - overall_min(sum(bytes)) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))`", "lensFormulaDocs.overall_metric": "indicateur : nombre", - "lensFormulaDocs.overall_min.documentation.markdown": "\nCalcule la valeur minimale d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle.\nD'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes.\n\nSi le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, `overall_min` calcule la valeur minimale pour toutes les dimensions, quelle que soit la fonction utilisée.\n\nExemple : Pourcentage de plage : \n`(sum(bytes) - overall_min(sum(bytes)) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))`\n", - "lensFormulaDocs.overall_sum.documentation.markdown": "\nCalcule la somme d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle.\nD'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes.\n\nSi le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, `overall_sum` calcule la somme pour toutes les dimensions, quelle que soit la fonction utilisée.\n\nExemple : Pourcentage total : \n`sum(bytes) / overall_sum(sum(bytes))`\n", + "lensFormulaDocs.overall_min.documentation.markdown": "Calcule la valeur minimale d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle. D'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes. Si le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, `overall_min` calcule la valeur minimale pour toutes les dimensions, quelle que soit la fonction utilisée. Exemple : Pourcentage de plage : `(sum(bytes) - overall_min(sum(bytes)) / (overall_max(sum(bytes)) - overall_min(sum(bytes)))`", + "lensFormulaDocs.overall_sum.documentation.markdown": "Calcule la somme d'un indicateur pour tous les points de données d'une série dans le graphique actuel. Une série est définie par une dimension à l'aide d'un histogramme de dates ou d'une fonction d'intervalle. D'autres dimensions permettant de répartir les données telles que les valeurs supérieures ou les filtres sont traitées en tant que séries distinctes. Si le graphique actuel n'utilise aucun histogramme de dates ou aucune fonction d'intervalle, `overall_sum` calcule la somme pour toutes les dimensions, quelle que soit la fonction utilisée. Exemple : Pourcentage du total : `sum(bytes) / overall_sum(sum(bytes))`", "lensFormulaDocs.overallAverage": "Moyenne globale", "lensFormulaDocs.overallMax": "Max général", "lensFormulaDocs.overallMin": "Min général", "lensFormulaDocs.overallSum": "Somme générale", "lensFormulaDocs.percentile": "Centile", - "lensFormulaDocs.percentile.documentation.markdown": "\nRenvoie le centile spécifié des valeurs d'un champ. Il s'agit de la valeur de n pour cent des valeurs présentes dans les documents.\n\nExemple : obtenir le nombre d'octets supérieurs à 95 % des valeurs : \n`percentile(bytes, percentile=95)`\n", + "lensFormulaDocs.percentile.documentation.markdown": "Renvoie le centile spécifié des valeurs d'un champ. Il s'agit de la valeur de n pour cent des valeurs présentes dans les documents. Exemple : Obtenir le nombre d'octets supérieurs à 95 % des valeurs : `percentile(bytes, percentile=95)`", "lensFormulaDocs.percentile.signature": "champ : chaîne, [percentile] : nombre", "lensFormulaDocs.percentileRank": "Rang centile", - "lensFormulaDocs.percentileRanks.documentation.markdown": "\nRenvoie le pourcentage de valeurs qui sont en dessous d'une certaine valeur. Par exemple, si une valeur est supérieure à 95 % des valeurs observées, elle est placée au 95e rang centile.\n\nExemple : Obtenir le pourcentage de valeurs qui sont en dessous de 100 : \n`percentile_rank(bytes, value=100)`\n", + "lensFormulaDocs.percentileRanks.documentation.markdown": "Renvoie le pourcentage de valeurs qui sont en dessous d'une certaine valeur. Par exemple, si une valeur est supérieure à 95 % des valeurs observées, elle est placée au 95e rang centile. Exemple : Obtenir le pourcentage de valeurs qui sont en dessous de 100 : `percentile_rank(bytes, value=100)`", "lensFormulaDocs.percentileRanks.signature": "champ : chaîne, [valeur] : nombre", "lensFormulaDocs.standardDeviation": "Écart-type", - "lensFormulaDocs.standardDeviation.documentation.markdown": "\nRenvoie la taille de la variation ou de la dispersion du champ. Cette fonction ne s’applique qu’aux champs numériques.\n\n#### Exemples\n\nPour obtenir l'écart-type d'un prix, utilisez `standard_deviation(price)`.\n\nPour obtenir la variance du prix des commandes passées au Royaume-Uni, utilisez `square(standard_deviation(price, kql='location:UK'))`.\n", + "lensFormulaDocs.standardDeviation.documentation.markdown": "Renvoie la taille de la variation ou de la dispersion du champ. Cette fonction ne s'applique qu'aux champs numériques. #### Exemples Pour obtenir l'écart-type d'un prix, utilisez `standard_deviation(price)`. Pour obtenir la variance du prix des commandes passées au Royaume-Uni, utilisez `square(standard_deviation(price, kql='location:UK'))`.", "lensFormulaDocs.string": "chaîne", "lensFormulaDocs.sum": "Somme", "lensFormulaDocs.time_range": "Plage temporelle", "lensFormulaDocs.time_scale": "indicateur : nombre, unité : s|m|h|d|w|M|y", - "lensFormulaDocs.time_scale.documentation.markdown": "\nCette fonction avancée est utile pour normaliser les comptes et les sommes sur un intervalle de temps spécifique. Elle permet l'intégration avec les indicateurs qui sont stockés déjà normalisés sur un intervalle de temps spécifique.\n\nVous pouvez faire appel à cette fonction uniquement si une fonction d'histogramme des dates est utilisée dans le graphique actuel.\n\nExemple : Un rapport comparant un indicateur déjà normalisé à un autre indicateur devant être normalisé. \n`normalize_by_unit(counter_rate(max(system.diskio.write.bytes)), unit='s') / last_value(apache.status.bytes_per_second)`\n", - "lensFormulaDocs.timeRange.help": "\nL'intervalle de temps spécifié, en millisecondes (ms).\n\nExemple : Quelle est la durée de la plage temporelle actuelle en (ms) ?\n`time_range()`\n\nExemple : Une moyenne statique par minute calculée avec l'intervalle de temps actuel :\n`(sum(bytes) / time_range()) * 1000 * 60`\n", + "lensFormulaDocs.time_scale.documentation.markdown": "Cette fonction avancée est utile pour normaliser les comptes et les sommes sur un intervalle de temps spécifique. Elle permet l'intégration avec les indicateurs qui sont stockés déjà normalisés sur un intervalle de temps spécifique. Vous pouvez faire appel à cette fonction uniquement si une fonction d'histogramme des dates est utilisée dans le graphique actuel. Exemple : Un rapport comparant un indicateur déjà normalisé à un autre indicateur devant être normalisé. `normalize_by_unit(counter_rate(max(system.diskio.write.bytes)), unit='s') / last_value(apache.status.bytes_per_second)`", + "lensFormulaDocs.timeRange.help": "L'intervalle de temps spécifié, en millisecondes (ms). Exemple : Quelle est la durée de la plage temporelle actuelle en (ms) ? `time_range()` Exemple : Une moyenne statique par minute calculée avec l'intervalle de temps actuel : `(sum(bytes) / time_range()) * 1000 * 60`", "lensFormulaDocs.timeScale": "Normaliser par unité", - "lensFormulaDocs.tinymath.absFunction.markdown": "\nCalcule une valeur absolue. Une valeur négative est multipliée par -1, une valeur positive reste identique.\n\nExemple : calculer la distance moyenne par rapport au niveau de la mer `abs(average(altitude))`\n ", - "lensFormulaDocs.tinymath.addFunction.markdown": "\nAjoute jusqu'à deux nombres.\nFonctionne également avec le symbole `+`.\n\nExemple : calculer la somme de deux champs\n\n`sum(price) + sum(tax)`\n\nExemple : compenser le compte par une valeur statique\n\n`add(count(), 5)`\n ", + "lensFormulaDocs.tinymath.absFunction.markdown": "Calcule une valeur absolue. Une valeur négative est multipliée par -1, une valeur positive reste identique. Exemple : calculer la distance moyenne par rapport au niveau de la mer `abs(average(altitude))`", + "lensFormulaDocs.tinymath.addFunction.markdown": "Ajoute jusqu'à deux nombres. Fonctionne également avec le symbole `+`. Exemple : Calculer la somme de deux champs `sum(price) + sum(tax)` Exemple : Compenser le compte par une valeur statique `add(count(), 5)`", "lensFormulaDocs.tinymath.base": "base", - "lensFormulaDocs.tinymath.cbrtFunction.markdown": "\nÉtablit la racine carrée de la valeur.\n\nExemple : calculer la longueur du côté à partir du volume\n`cbrt(last_value(volume))`\n ", - "lensFormulaDocs.tinymath.ceilFunction.markdown": "\nArrondit le plafond de la valeur au chiffre supérieur.\n\nExemple : arrondir le prix au dollar supérieur\n`ceil(sum(price))`\n ", - "lensFormulaDocs.tinymath.clampFunction.markdown": "\nÉtablit une limite minimale et maximale pour la valeur.\n\nExemple : s'assurer de repérer les valeurs aberrantes\n````\nclamp(\n average(bytes),\n percentile(bytes, percentile=5),\n percentile(bytes, percentile=95)\n)\n````\n", + "lensFormulaDocs.tinymath.cbrtFunction.markdown": "Établit la racine carrée de la valeur. Exemple : Calculer la longueur du côté à partir du volume `cbrt(last_value(volume))`", + "lensFormulaDocs.tinymath.ceilFunction.markdown": "Arrondit le plafond de la valeur au chiffre supérieur. Exemple : Arrondir le prix au dollar supérieur `ceil(sum(price))`", + "lensFormulaDocs.tinymath.clampFunction.markdown": "Établit une limite minimale et maximale pour la valeur. Exemple : S'assurer de repérer les valeurs aberrantes ``` clamp( average(bytes), percentile(bytes, percentile=5), percentile(bytes, percentile=95) ) ```", "lensFormulaDocs.tinymath.condition": "condition", - "lensFormulaDocs.tinymath.cubeFunction.markdown": "\nCalcule le cube d'un nombre.\n\nExemple : calculer le volume à partir de la longueur du côté\n`cube(last_value(length))`\n ", + "lensFormulaDocs.tinymath.cubeFunction.markdown": "Calcule le cube d'un nombre. Exemple : Calculer le volume à partir de la longueur du côté `cube(last_value(length))`", "lensFormulaDocs.tinymath.decimals": "décimales", - "lensFormulaDocs.tinymath.defaultFunction.markdown": "\nRenvoie une valeur numérique par défaut lorsque la valeur est nulle.\n\nExemple : Renvoie -1 lorsqu'un champ ne contient aucune donnée.\n`defaults(average(bytes), -1)`\n", + "lensFormulaDocs.tinymath.defaultFunction.markdown": "Renvoie une valeur numérique par défaut lorsque la valeur est nulle. Exemple : Renvoie -1 si un champ n'a pas de données `defaults(average(bytes), -1)`", "lensFormulaDocs.tinymath.defaultValue": "par défaut", - "lensFormulaDocs.tinymath.divideFunction.markdown": "\nDivise le premier nombre par le deuxième.\nFonctionne également avec le symbole `/`.\n\nExemple : calculer la marge bénéficiaire\n`sum(profit) / sum(revenue)`\n\nExemple : `divide(sum(bytes), 2)`\n ", - "lensFormulaDocs.tinymath.eqFunction.markdown": "\nEffectue une comparaison d'égalité entre deux valeurs.\nÀ utiliser en tant que condition pour la fonction de comparaison `ifelse`.\nFonctionne également avec le symbole `==`.\n\nExemple : Renvoie \"true\" si la moyenne d'octets est égale à la quantité de mémoire moyenne.\n`average(bytes) == average(memory)`\n\nExemple : `eq(sum(bytes), 1000000)`\n ", - "lensFormulaDocs.tinymath.expFunction.markdown": "\nÉlève *e* à la puissance n.\n\nExemple : calculer la fonction exponentielle naturelle\n\n`exp(last_value(duration))`\n ", - "lensFormulaDocs.tinymath.fixFunction.markdown": "\nPour les valeurs positives, part du bas. Pour les valeurs négatives, part du haut.\n\nExemple : arrondir à zéro\n`fix(sum(profit))`\n ", - "lensFormulaDocs.tinymath.floorFunction.markdown": "\nArrondit à la valeur entière inférieure la plus proche.\n\nExemple : arrondir un prix au chiffre inférieur\n`floor(sum(price))`\n ", - "lensFormulaDocs.tinymath.gteFunction.markdown": "\nEffectue une comparaison de supériorité entre deux valeurs.\nÀ utiliser en tant que condition pour la fonction de comparaison `ifelse`.\nFonctionne également avec le symbole `>=`.\n\nExemple : Renvoie \"true\" si la moyenne d'octets est supérieure ou égale à la quantité moyenne de mémoire.\n`average(bytes) >= average(memory)`\n\nExemple : `gte(average(bytes), 1000)`\n ", - "lensFormulaDocs.tinymath.gtFunction.markdown": "\nEffectue une comparaison de supériorité entre deux valeurs.\nÀ utiliser en tant que condition pour la fonction de comparaison `ifelse`.\nFonctionne également avec le symbole `>`.\n\nExemple : Renvoie \"true\" si la moyenne d'octets est supérieure à la quantité moyenne de mémoire.\n`average(bytes) > average(memory)`\n\nExemple : `gt(average(bytes), 1000)`\n ", - "lensFormulaDocs.tinymath.ifElseFunction.markdown": "\nRenvoie une valeur selon si l'élément de condition est \"true\" ou \"false\".\n\nExemple : Revenus moyens par client, mais dans certains cas, l'ID du client n'est pas fourni, et le client est alors compté comme client supplémentaire.\n`sum(total)/(unique_count(customer_id) + ifelse( count() > count(kql='customer_id:*'), 1, 0))`\n ", + "lensFormulaDocs.tinymath.divideFunction.markdown": "Divise le premier nombre par le deuxième. Fonctionne également avec le symbole `/`. Exemple : Calculer la marge bénéficiaire `sum(profit) / sum(revenue)` Exemple : `divide(sum(bytes), 2)`", + "lensFormulaDocs.tinymath.eqFunction.markdown": "Effectue une comparaison d'égalité entre deux valeurs. À utiliser en tant que condition pour la fonction de comparaison `ifelse`. Fonctionne également avec le symbole `==`. Exemple : Renvoie \"true\" si la moyenne d'octets est égale à la quantité de mémoire moyenne `average(bytes) == average(memory)` Exemple : `eq(sum(bytes), 1000000)`", + "lensFormulaDocs.tinymath.expFunction.markdown": "Élève *e* à la puissance n. Exemple : Calculer la fonction exponentielle naturelle `exp(last_value(duration))`", + "lensFormulaDocs.tinymath.fixFunction.markdown": "Pour les valeurs positives, part du bas. Pour les valeurs négatives, part du haut. Exemple : Arrondir vers zéro `fix(sum(profit))`", + "lensFormulaDocs.tinymath.floorFunction.markdown": "Arrondit à la valeur entière inférieure la plus proche. Exemple : Arrondir un prix à la baisse `floor(sum(price))`", + "lensFormulaDocs.tinymath.gteFunction.markdown": "Effectue une comparaison de supériorité entre deux valeurs. À utiliser en tant que condition pour la fonction de comparaison `ifelse`. Fonctionne également avec le symbole `>=`. Exemple : Renvoie \"true\" si la moyenne d'octets est supérieure ou égale à la quantité de mémoire moyenne `average(bytes) >= average(memory)` Exemple : `gte(average(bytes), 1000)`", + "lensFormulaDocs.tinymath.gtFunction.markdown": "Effectue une comparaison de supériorité entre deux valeurs. À utiliser en tant que condition pour la fonction de comparaison `ifelse`. Fonctionne également avec le symbole `>`. Exemple : Renvoie \"true\" si la moyenne d'octets est supérieure à la quantité de mémoire moyenne `average(bytes) > average(memory)` Exemple : `gt(average(bytes), 1000)`", + "lensFormulaDocs.tinymath.ifElseFunction.markdown": "Renvoie une valeur selon si l'élément de condition est \"true\" ou \"false\". Exemple : Revenus moyens par client, mais dans certains cas, l'ID du client n'est pas fourni, et le client est alors compté comme client supplémentaire `sum(total)/(unique_count(customer_id) + ifelse( count() > count(kql='customer_id:*'), 1, 0))`", "lensFormulaDocs.tinymath.left": "gauche", - "lensFormulaDocs.tinymath.logFunction.markdown": "\nÉtablit un logarithme avec base optionnelle. La base naturelle *e* est utilisée par défaut.\n\nExemple : calculer le nombre de bits nécessaire au stockage de valeurs\n````\nlog(sum(bytes))\nlog(sum(bytes), 2)\n````\n ", - "lensFormulaDocs.tinymath.lteFunction.markdown": "\nEffectue une comparaison d'infériorité ou de supériorité entre deux valeurs.\nÀ utiliser en tant que condition pour la fonction de comparaison `ifelse`.\nFonctionne également avec le symbole `<=`.\n\nExemple : Renvoie \"true\" si la moyenne d'octets est inférieure ou égale à la quantité moyenne de mémoire.\n`average(bytes) <= average(memory)`\n\nExemple : `lte(average(bytes), 1000)`\n ", - "lensFormulaDocs.tinymath.ltFunction.markdown": "\nEffectue une comparaison d'infériorité entre deux valeurs.\nÀ utiliser en tant que condition pour la fonction de comparaison `ifelse`.\nFonctionne également avec le symbole `<`.\n\nExemple : Renvoie \"true\" si la moyenne d'octets est inférieure à la quantité moyenne de mémoire.\n`average(bytes) <= average(memory)`\n\nExemple : `lt(average(bytes), 1000)`\n ", + "lensFormulaDocs.tinymath.logFunction.markdown": "Établit un logarithme avec base optionnelle. La base naturelle *e* est utilisée par défaut. Exemple : Calculer le nombre de bits nécessaire au stockage de valeurs ``` log(sum(bytes)) log(sum(bytes), 2) ```", + "lensFormulaDocs.tinymath.lteFunction.markdown": "Effectue une comparaison d'infériorité ou de supériorité entre deux valeurs. À utiliser en tant que condition pour la fonction de comparaison `ifelse`. Fonctionne également avec le symbole `<=`. Exemple : Renvoie \"true\" si la moyenne d'octets est inférieure ou égale à la quantité de mémoire moyenne `average(bytes) <= average(memory)` Exemple : `lte(average(bytes), 1000)`", + "lensFormulaDocs.tinymath.ltFunction.markdown": "Effectue une comparaison d'infériorité entre deux valeurs. À utiliser en tant que condition pour la fonction de comparaison `ifelse`. Fonctionne également avec le symbole `<`. Exemple : Renvoie \"true\" si la moyenne d'octets est inférieure à la quantité de mémoire moyenne `average(bytes) <= average(memory)` Exemple : `lt(average(bytes), 1000)`", "lensFormulaDocs.tinymath.max": "max", - "lensFormulaDocs.tinymath.maxFunction.markdown": "\nTrouve la valeur maximale entre deux nombres.\n\nExemple : Trouver le maximum entre deux moyennes de champs\n`pick_max(average(bytes), average(memory))`\n ", + "lensFormulaDocs.tinymath.maxFunction.markdown": "Trouve la valeur maximale entre deux nombres. Exemple : Trouver la valeur maximale entre deux moyennes de champs `pick_max(average(bytes), average(memory))`", "lensFormulaDocs.tinymath.min": "min", - "lensFormulaDocs.tinymath.minFunction.markdown": "\nTrouve la valeur minimale entre deux nombres.\n\nExemple : Trouver le minimum entre deux moyennes de champs\n`pick_min(average(bytes), average(memory))`\n ", - "lensFormulaDocs.tinymath.modFunction.markdown": "\nÉtablit le reste après division de la fonction par un nombre.\n\nExemple : calculer les trois derniers chiffres d'une valeur\n`mod(sum(price), 1000)`\n ", - "lensFormulaDocs.tinymath.multiplyFunction.markdown": "\nMultiplie deux nombres.\nFonctionne également avec le symbole `*`.\n\nExemple : calculer le prix après application du taux d'imposition courant\n`sum(bytes) * last_value(tax_rate)`\n\nExemple : calculer le prix après application du taux d'imposition constant\n`multiply(sum(price), 1.2)`\n ", - "lensFormulaDocs.tinymath.powFunction.markdown": "\nÉlève la valeur à une puissance spécifique. Le deuxième argument est obligatoire.\n\nExemple : calculer le volume en fonction de la longueur du côté\n`pow(last_value(length), 3)`\n ", + "lensFormulaDocs.tinymath.minFunction.markdown": "Trouve la valeur minimale entre deux nombres. Exemple : Trouver la valeur minimale entre deux moyennes de champs `pick_min(average(bytes), average(memory))`", + "lensFormulaDocs.tinymath.modFunction.markdown": "Établit le reste après division de la fonction par un nombre. Exemple : Calculer les trois derniers chiffres d'une valeur `mod(sum(price), 1000)`", + "lensFormulaDocs.tinymath.multiplyFunction.markdown": "Multiplie deux nombres. Fonctionne également avec le symbole `*`. Exemple : Calculer le prix après application du taux d'imposition actuel `sum(bytes) * last_value(tax_rate)` Exemple : Calculer le prix après application du taux d'imposition constant `multiply(sum(price), 1.2)`", + "lensFormulaDocs.tinymath.powFunction.markdown": "Élève la valeur à une puissance spécifique. Le deuxième argument est obligatoire. Exemple : Calculer le volume en fonction de la longueur du côté `pow(last_value(length), 3)`", "lensFormulaDocs.tinymath.right": "droite", - "lensFormulaDocs.tinymath.roundFunction.markdown": "\nArrondit à un nombre donné de décimales, 0 étant la valeur par défaut.\n\nExemples : arrondir au centième\n````\nround(sum(bytes))\nround(sum(bytes), 2)\n````\n ", - "lensFormulaDocs.tinymath.sqrtFunction.markdown": "\nÉtablit la racine carrée d'une valeur positive uniquement.\n\nExemple : calculer la longueur du côté en fonction de la surface\n`sqrt(last_value(area))`\n ", - "lensFormulaDocs.tinymath.squareFunction.markdown": "\nÉlève la valeur à la puissance 2.\n\nExemple : calculer l’aire en fonction de la longueur du côté\n`square(last_value(length))`\n ", - "lensFormulaDocs.tinymath.subtractFunction.markdown": "\nSoustrait le premier nombre du deuxième.\nFonctionne également avec le symbole `-`.\n\nExemple : calculer la plage d'un champ\n`subtract(max(bytes), min(bytes))`\n ", + "lensFormulaDocs.tinymath.roundFunction.markdown": "Arrondit à un nombre donné de décimales, 0 étant la valeur par défaut. Exemple : Arrondir au centième ``` round(sum(bytes)) round(sum(bytes), 2) ```", + "lensFormulaDocs.tinymath.sqrtFunction.markdown": "Établit la racine carrée d'une valeur positive uniquement. Exemple : Calculer la longueur d'un côté en fonction de la surface `sqrt(last_value(area))`", + "lensFormulaDocs.tinymath.squareFunction.markdown": "Élève la valeur à la puissance 2. Exemple : Calculer la surface en fonction de la longueur du côté `square(last_value(length))`", + "lensFormulaDocs.tinymath.subtractFunction.markdown": "Soustrait le premier nombre du deuxième. Fonctionne également avec le symbole `-`. Exemple : Calculer la plage d'un champ `subtract(max(bytes), min(bytes))`", "lensFormulaDocs.tinymath.value": "valeur", "links.contentManagement.saveModalTitle": "Enregistrer le panneau {contentId} dans la bibliothèque", "links.dashboardLink.description": "Accéder au tableau de bord", @@ -5786,14 +6393,16 @@ "links.dashboardLink.editor.loadingDashboardLabel": "Chargement...", "links.dashboardLink.type": "Lien du tableau de bord", "links.description": "Utiliser des liens pour accéder aux tableaux de bord et aux sites web couramment utilisés.", + "links.displayName": "liens", "links.editor.addButtonLabel": "Ajouter un lien", "links.editor.cancelButtonLabel": "Fermer", "links.editor.deleteLinkTitle": "Supprimer le lien {label}", "links.editor.editLinkTitle.hasLabel": "Modifier le lien {label}", "links.editor.horizontalLayout": "Horizontal", - "links.editor.unableToSaveToastTitle": "Erreur lors de l'enregistrement du Panneau de liens", + "links.editor.unableToSaveToastTitle": "Erreur lors de l'enregistrement du panneau de liens", "links.editor.updateButtonLabel": "Mettre à jour le lien", "links.editor.verticalLayout": "Vertical", + "links.embeddable.unsupportedLinkTypeError": "Type de lien non pris en charge", "links.externalLink.description": "Accéder à l'URL", "links.externalLink.displayName": "URL", "links.externalLink.editor.disallowedUrlError": "Cette URL n'est pas autorisée par votre administrateur. Reportez-vous à la configuration \"externalUrl.policy\".", @@ -5834,7 +6443,14 @@ "managedContentBadge.text": "Géré", "management.breadcrumb": "Gestion de la Suite", "management.landing.header": "Bienvenue dans Gestion de la Suite {version}", + "management.landing.solution.header": "Gestion de la Suite {version}", + "management.landing.solution.subhead": "Gérez vos {indicesLink}, {dataViewsLink}, {ingestPipelinesLink}, {usersLink}, et plus encore.", + "management.landing.solution.viewAllPagesButton": "Afficher toutes les pages", "management.landing.subhead": "Gérez vos index, vues de données, objets enregistrés, paramètres Kibana et plus encore.", + "management.landing.subhead.dataViewsLink": "Les vues de données sont introuvables", + "management.landing.subhead.indicesLink": "index système non migrés", + "management.landing.subhead.ingestPipelinesLink": "pipelines d'ingestion", + "management.landing.subhead.usersLink": "utilisateurs", "management.landing.text": "Vous trouverez une liste complète des applications dans le menu de gauche.", "management.landing.withCardNavigation.accessTitle": "Accès", "management.landing.withCardNavigation.alertsTitle": "Alertes et informations exploitables", @@ -5843,6 +6459,7 @@ "management.landing.withCardNavigation.contentTitle": "Contenu", "management.landing.withCardNavigation.dataQualityDescription": "Recherchez et gérez les problèmes de qualité dans vos données de logs.", "management.landing.withCardNavigation.dataTitle": "Données", + "management.landing.withCardNavigation.dataUsageDescription": "Afficher l'utilisation et la conservation des données.", "management.landing.withCardNavigation.dataViewsDescription": "Créez et gérez les données Elasticsearch sélectionnées pour l'exploration.", "management.landing.withCardNavigation.fileManagementDescription": "Accédez à tous les fichiers importés.", "management.landing.withCardNavigation.indexmanagementDescription": "Configurez et assurez la maintenance de vos index Elasticsearch pour le stockage et la récupération des données.", @@ -5858,6 +6475,7 @@ "management.landing.withCardNavigation.rolesDescription": "Créez des rôles uniques pour ce projet et combinez l'ensemble exact de privilèges dont vos utilisateurs ont besoin.", "management.landing.withCardNavigation.rulesDescription": "Définissez à quel moment générer des alertes et des notifications.", "management.landing.withCardNavigation.settingsDescription": "Contrôlez les comportements des projets, tels que l'affichage des dates et le tri par défaut.", + "management.landing.withCardNavigation.spacesDescription": "Organisez vos objets enregistrés en catégories représentatives.", "management.landing.withCardNavigation.tagsDescription": "Organisez, recherchez et filtrez vos objets enregistrés en fonction de critères spécifiques.", "management.landing.withCardNavigation.transformDescription": "Organisez vos données ou copiez les derniers documents dans un index centré sur les entités.", "management.nav.label": "Gestion", @@ -5930,6 +6548,10 @@ "management.settings.spaceCalloutSubtitle": "Les modifications seront uniquement appliquées à l'espace actuel. Ces paramètres sont destinés aux utilisateurs avancés, car des configurations incorrectes peuvent avoir une incidence négative sur des aspects de Kibana.", "management.settings.spaceCalloutTitle": "Les modifications affecteront l'espace actuel.", "management.settings.spaceSettingsTabTitle": "Paramètres de l'espace", + "management.stackManagement.managementDescription": "La console centrale de gestion de la Suite Elastic.", + "management.stackManagement.managementLabel": "Gestion de la Suite", + "management.stackManagement.title": "Gestion de la Suite", + "monaco.esql.hover.acceptableTypes": "Types acceptables", "monaco.esql.hover.policyEnrichedFields": "**Champs**", "monaco.esql.hover.policyIndexes": "**Indexes**", "monaco.esql.hover.policyMatchingField": "**Champ correspondant**", @@ -5937,6 +6559,9 @@ "monaco.painlessLanguage.autocomplete.emitKeywordDescription": "Émettre une valeur sans rien renvoyer", "monaco.painlessLanguage.autocomplete.fieldValueDescription": "Récupérer la valeur du champ \"{fieldName}\"", "monaco.painlessLanguage.autocomplete.paramsKeywordDescription": "Accéder aux variables transmises dans le script", + "navigation.ui_settings.params.defaultRoute.defaultRouteTitle": "Chemin par défaut", + "navigation.uiSettings.defaultRoute.defaultRouteIsRelativeValidationMessage": "Doit être une URL relative.", + "navigation.uiSettings.defaultRoute.defaultRouteText": "Ce paramètre spécifie le chemin par défaut lors de l'ouverture de Kibana. Vous pouvez utiliser ce paramètre pour modifier la page de destination à l'ouverture de Kibana. Le chemin doit être une URL relative.", "newsfeed.emptyPrompt.noNewsText": "Si votre instance Kibana n'a pas accès à Internet, demandez à votre administrateur de désactiver cette fonctionnalité. Sinon, nous continuerons d'essayer de récupérer les actualités.", "newsfeed.emptyPrompt.noNewsTitle": "Pas d'actualités ?", "newsfeed.flyoutList.closeButtonLabel": "Fermer", @@ -6283,6 +6908,10 @@ "savedSearch.kibana_context.savedSearchId.help": "Spécifier l'ID de recherche enregistrée à utiliser pour les requêtes et les filtres", "savedSearch.kibana_context.timeRange.help": "Spécifier le filtre de plage temporelle Kibana", "savedSearch.legacyURLConflict.errorMessage": "Cette recherche a la même URL qu'un alias hérité. Désactiver l'alias pour résoudre cette erreur : {json}", + "searchApiKeysComponents.apiKeyForm.createButton": "Créer une clé d'API", + "searchApiKeysComponents.apiKeyForm.noUserPrivileges": "Vous n'avez pas accès à la gestion des clés d'API", + "searchApiKeysComponents.apiKeyForm.showApiKey": "Afficher la clé d'API", + "searchApiKeysComponents.apiKeyForm.title": "Clé d'API", "searchApiPanels.cloudIdDetails.cloudId.description": "Des bibliothèques et des connecteurs clients peuvent utiliser cet identificateur unique propre à Elastic Cloud.", "searchApiPanels.cloudIdDetails.cloudId.title": "Identifiant du cloud", "searchApiPanels.cloudIdDetails.description": "Soyez prêt à ingérer et rechercher vos données en choisissant une option de connexion :", @@ -6305,25 +6934,37 @@ "searchApiPanels.pipeline.overview.pipelineHandling.description": "Gérez les exceptions d'erreur, exécutez un autre pipeline ou redirigez les documents vers un autre index", "searchApiPanels.pipeline.overview.pipelineHandling.title": "Traitement du pipeline", "searchApiPanels.preprocessData.overview.arrayJsonHandling.learnMore": "En savoir plus", + "searchApiPanels.preprocessData.overview.arrayJsonHandling.learnMore.ariaLabel": "En savoir plus sur la gestion des tableaux/JSON", "searchApiPanels.preprocessData.overview.dataEnrichment.description": "Ajouter des informations des sources externes ou appliquer des transformations à vos documents pour une recherche plus contextuelle et pertinente.", "searchApiPanels.preprocessData.overview.dataEnrichment.learnMore": "En savoir plus", + "searchApiPanels.preprocessData.overview.dataEnrichment.learnMore.ariaLabel": "En savoir plus sur l'enrichissement de données", "searchApiPanels.preprocessData.overview.dataEnrichment.title": "Enrichissement des données", "searchApiPanels.preprocessData.overview.dataFiltering.learnMore": "En savoir plus", + "searchApiPanels.preprocessData.overview.dataFiltering.learnMore.ariaLabel": "En savoir plus sur le filtrage des données", "searchApiPanels.preprocessData.overview.dataTransformation.learnMore": "En savoir plus", + "searchApiPanels.preprocessData.overview.dataTransformation.learnMore.ariaLabel": "En savoir plus sur la transformation des données", "searchApiPanels.preprocessData.overview.pipelineHandling.learnMore": "En savoir plus", + "searchApiPanels.preprocessData.overview.pipelineHandling.learnMore.ariaLabel": "En savoir plus sur la gestion des pipelines", + "searchApiPanels.welcomeBanner.codeBox.copyAriaLabel": "Copier l'extrait de code {context}", "searchApiPanels.welcomeBanner.codeBox.copyButtonLabel": "Copier", + "searchApiPanels.welcomeBanner.codeBox.copyLabel": "Copier l'extrait de code", + "searchApiPanels.welcomeBanner.codeBox.selectAriaLabel": "{context} {languageName}", + "searchApiPanels.welcomeBanner.codeBox.selectChangeAriaLabel": "Modifier le langage en {languageName} pour chaque instance de cette page", + "searchApiPanels.welcomeBanner.codeBox.selectLabel": "Sélectionner un langage de programmation pour l'extrait de code {languageName}", "searchApiPanels.welcomeBanner.header.description": "Configurez votre client de langage de programmation, ingérez des données, et vous serez prêt à commencer vos recherches en quelques minutes.", "searchApiPanels.welcomeBanner.header.greeting.customTitle": "👋 Bonjour {name} !", "searchApiPanels.welcomeBanner.header.greeting.defaultTitle": "👋 Bonjour", "searchApiPanels.welcomeBanner.header.title": "Lancez-vous avec Elasticsearch", "searchApiPanels.welcomeBanner.ingestData.alternativeOptions": "Autres options d'ingestion", "searchApiPanels.welcomeBanner.ingestData.alternativeOptions.beatsDescription": "Des agents légers conçus pour le transfert de données pour Elasticsearch. Utilisez Beats pour envoyer des données opérationnelles depuis vos serveurs.", + "searchApiPanels.welcomeBanner.ingestData.alternativeOptions.beatsDocumentation.ariaLabel": "Documentation Beats", "searchApiPanels.welcomeBanner.ingestData.alternativeOptions.beatsDocumentationLabel": "Documentation", "searchApiPanels.welcomeBanner.ingestData.alternativeOptions.beatsTitle": "Beats", "searchApiPanels.welcomeBanner.ingestData.alternativeOptions.logstashDescription": "Pipeline de traitement des données à usage général pour Elasticsearch. Utilisez Logstash pour extraire et transformer les données d'une variétés d'entrées et de sorties.", + "searchApiPanels.welcomeBanner.ingestData.alternativeOptions.logstashDocumentation.ariaLabel": "Documentation Logstash", "searchApiPanels.welcomeBanner.ingestData.alternativeOptions.logstashDocumentationLabel": "Documentation", "searchApiPanels.welcomeBanner.ingestData.alternativeOptions.logstashTitle": "Logstash", - "searchApiPanels.welcomeBanner.ingestData.description": "Ajoutez des données à votre flux de données ou à votre index pour les rendre interrogeables à l'aide de l'API. ", + "searchApiPanels.welcomeBanner.ingestData.description": "Ajoutez des données à votre flux de données ou à votre index pour les rendre interrogeables à l'aide de l'API.", "searchApiPanels.welcomeBanner.ingestData.title": "Ingérer des données", "searchApiPanels.welcomeBanner.ingestPipelinePanel.description": "Vous pouvez utiliser des pipelines d'ingestion pour prétraiter vos données avant leur indexation dans Elasticsearch.", "searchApiPanels.welcomeBanner.ingestPipelinePanel.managedBadge": "Géré", @@ -6336,12 +6977,12 @@ "searchApiPanels.welcomeBanner.installClient.description": "Vous devez d'abord installer le client de langage de programmation de votre choix.", "searchApiPanels.welcomeBanner.installClient.title": "Installer un client", "searchApiPanels.welcomeBanner.panels.learnMore": "En savoir plus", - "searchApiPanels.welcomeBanner.selectClient.apiRequestConsoleDocLink": "Exécuter des requêtes d’API dans la console ", + "searchApiPanels.welcomeBanner.selectClient.apiRequestConsoleDocLink": "Exécuter des requêtes d’API dans la console", "searchApiPanels.welcomeBanner.selectClient.callout.description": "Avec la console, vous pouvez directement commencer à utiliser nos API REST. Aucune installation n’est requise.", "searchApiPanels.welcomeBanner.selectClient.callout.link": "Essayez la console maintenant", "searchApiPanels.welcomeBanner.selectClient.callout.title": "Lancez-vous dans la console", - "searchApiPanels.welcomeBanner.selectClient.description": "Elastic construit et assure la maintenance des clients dans plusieurs langues populaires et notre communauté a contribué à beaucoup d'autres. Sélectionnez votre client de langage favori ou explorez la {console} pour commencer.", - "searchApiPanels.welcomeBanner.selectClient.elasticsearchClientDocLink": "Clients d'Elasticsearch ", + "searchApiPanels.welcomeBanner.selectClient.description": "Elastic construit et assure la maintenance des clients dans plusieurs langues populaires et notre communauté a contribué à beaucoup d'autres. Sélectionnez votre client de langage favori ou découvrez la console pour commencer.", + "searchApiPanels.welcomeBanner.selectClient.elasticsearchClientDocLink": "Clients d'Elasticsearch", "searchApiPanels.welcomeBanner.selectClient.heading": "Choisissez-en un", "searchApiPanels.welcomeBanner.selectClient.title": "Sélectionner votre client", "searchConnectors.config.invalidInteger": "{label} doit être un nombre entier.", @@ -6353,7 +6994,7 @@ "searchConnectors.configurationConnector.config.error.title": "Erreur de connecteur", "searchConnectors.configurationConnector.config.noConfigCallout.description": "Ce connecteur ne possède aucun champ de configuration. Votre connecteur a-t-il pu se connecter avec succès à Elasticsearch et définir sa configuration ?", "searchConnectors.configurationConnector.config.noConfigCallout.title": "Aucun champ de configuration", - "searchConnectors.configurationConnector.config.submitButton.title": "Enregistrer la configuration", + "searchConnectors.configurationConnector.config.submitButton.title": "Sauvegarder et synchroniser", "searchConnectors.connector.documentLevelSecurity.enablePanel.description": "Vous permet de contrôler les documents auxquels peuvent accéder les utilisateurs, selon leurs autorisations. Cela permet de vous assurer que les résultats de recherche ne renvoient que des informations pertinentes et autorisées pour les utilisateurs, selon leurs rôles.", "searchConnectors.connector.documentLevelSecurity.enablePanel.heading": "Sécurité au niveau du document", "searchConnectors.connectors.subscriptionLabel": "Plans d'abonnement", @@ -6570,7 +7211,7 @@ "searchConnectors.nativeConnectors.box.includeInheritedUsersTooltip": "Incluez les groupes et les utilisateurs hérités lors de l'indexation des autorisations. L'activation de ce champ configurable entraînera une dégradation significative des performances.", "searchConnectors.nativeConnectors.box.name": "Box", "searchConnectors.nativeConnectors.box.pathLabel": "Chemin permettant de récupérer les fichiers/dossiers", - "searchConnectors.nativeConnectors.box.pathTooltip": "Le chemin est ignoré lorsque des règles de synchronisation avancées sont appliquées. ", + "searchConnectors.nativeConnectors.box.pathTooltip": "Le chemin est ignoré lorsque des règles de synchronisation avancées sont appliquées.", "searchConnectors.nativeConnectors.box.refreshTokenLabel": "Token d'actualisation", "searchConnectors.nativeConnectors.boxTooltip.name": "Box", "searchConnectors.nativeConnectors.confluence.indexLabelsLabel": "Activer les étiquettes d'indexation", @@ -6772,6 +7413,7 @@ "searchConnectors.nativeConnectors.sharepoint_online.configuration.useDocumentLevelSecurityLabel": "Activer la sécurité au niveau du document", "searchConnectors.nativeConnectors.sharepoint_online.configuration.useDocumentLevelSecurityTooltip": "La sécurité au niveau du document préserve dans Elasticsearch les identités et permissions paramétrées dans Sharepoint Online. Ces métadonnées sont ajoutées à votre document Elasticsearch afin que vous puissiez contrôler l'accès en lecture des utilisateurs et des groupes. La synchronisation de contrôle d'accès garantit que ces métadonnées sont correctement actualisées.", "searchConnectors.nativeConnectors.sharepoint_online.name": "SharePoint en ligne", + "searchConnectors.nativeConnectors.sharepoint_server.configuration.authentication": "Authentification", "searchConnectors.nativeConnectors.sharepoint_server.configuration.fetchUniqueListItemPermissionsLabel": "Récupérer les autorisations d'un élément de liste unique", "searchConnectors.nativeConnectors.sharepoint_server.configuration.fetchUniqueListItemPermissionsTooltip": "Activer cette option pour récupérer les autorisations d'un élément de liste unique. Ce paramètre est susceptible d'augmenter le délai de synchronisation. Si ce paramètre est désactivé, un élément de liste hérite des permissions de son site parent.", "searchConnectors.nativeConnectors.sharepoint_server.configuration.fetchUniqueListPermissionsLabel": "Récupérer les autorisations de liste unique", @@ -6781,6 +7423,8 @@ "searchConnectors.nativeConnectors.sharepoint_server.configuration.site_collections": "Liste de collections de sites SharePoint séparées par des virgules à indexer", "searchConnectors.nativeConnectors.sharepoint_server.configuration.username": "Nom d'utilisateur du serveur SharePoint", "searchConnectors.nativeConnectors.sharepoint_server.name": "Serveur SharePoint", + "searchConnectors.nativeConnectors.sharepoint_server.options.basicLabel": "De base", + "searchConnectors.nativeConnectors.sharepoint_server.options.ntlmLabel": "NTLM", "searchConnectors.nativeConnectors.slack.autoJoinChannels.label": "Rejoindre automatiquement les canaux", "searchConnectors.nativeConnectors.slack.autoJoinChannels.tooltip": "Le bot de l'application Slack pourra seulement lire l'historique des conversations des canaux qu'il a rejoints. L’option par défaut nécessite qu'il soit invité manuellement aux canaux. L'activation de cette option lui permet de s'inviter automatiquement sur tous les canaux publics.", "searchConnectors.nativeConnectors.slack.fetchLastNDays.label": "Nombre de jours d'historique de messages à récupérer", @@ -6865,8 +7509,11 @@ "searchIndexDocuments.result.expandTooltip.showMore": "Afficher {amount} champs en plus", "searchIndexDocuments.result.header.metadata.deleteDocument": "Supprimer le document", "searchIndexDocuments.result.header.metadata.icon.ariaLabel": "Métadonnées pour le document : {id}", + "searchIndexDocuments.result.header.metadata.score": "Score", "searchIndexDocuments.result.header.metadata.title": "Métadonnées du document", "searchIndexDocuments.result.title.id": "ID de document : {id}", + "searchIndexDocuments.result.value.denseVector.copy": "Copier le vecteur", + "searchIndexDocuments.result.value.denseVector.dimLabel": "{value} dimensions", "searchResponseWarnings.badgeButtonLabel": "{warningCount} {warningCount, plural, one {avertissement} other {avertissements}}", "searchResponseWarnings.description.multipleClusters": "Ces clusters ont rencontré des problèmes lors du renvoi des données et les résultats pourraient être incomplets.", "searchResponseWarnings.description.singleCluster": "Ce cluster a rencontré des problèmes lors du renvoi des données et les résultats pourraient être incomplets.", @@ -6874,6 +7521,7 @@ "searchResponseWarnings.title.clustersClause": "Un problème est survenu avec {nonSuccessfulClustersCount} {nonSuccessfulClustersCount, plural, one {cluster} other {clusters}}", "searchResponseWarnings.title.clustersClauseAndRequestsClause": "{clustersClause} pour {requestsCount} requêtes", "searchResponseWarnings.viewDetailsButtonLabel": "Afficher les détails", + "securitySolutionPackages.alertAssignments.upsell": "Passer à {requiredLicense} pour utiliser les affectations d'alertes", "securitySolutionPackages.alertSuppressionRuleDetails.upsell": "La suppression d'alertes est configurée mais elle ne sera pas appliquée en raison d'une licence insuffisante", "securitySolutionPackages.alertSuppressionRuleForm.upsell": "La suppression d'alertes est activée avec la licence {requiredLicense} ou supérieure", "securitySolutionPackages.beta.label": "Bêta", @@ -6885,53 +7533,83 @@ "securitySolutionPackages.dataTable.eventsTab.unit": "{totalCount, plural, =1 {alerte} other {alertes}}", "securitySolutionPackages.dataTable.loadingEventsDataLabel": "Chargement des événements", "securitySolutionPackages.dataTable.unit": "{totalCount, plural, =1 {alerte} other {alertes}}", + "securitySolutionPackages.ecsDataQualityDashboard.actions.askAssistant": "Demander à l'assistant", "securitySolutionPackages.ecsDataQualityDashboard.addToCaseSuccessToast": "Résultats de qualité des données ajoutés au cas", "securitySolutionPackages.ecsDataQualityDashboard.addToNewCaseButton": "Ajouter au nouveau cas", + "securitySolutionPackages.ecsDataQualityDashboard.all": "Tous", + "securitySolutionPackages.ecsDataQualityDashboard.allFields": "Tous les champs", "securitySolutionPackages.ecsDataQualityDashboard.allTab.allFieldsTableTitle": "Tous les champs - {indexName}", "securitySolutionPackages.ecsDataQualityDashboard.cancelButton": "Annuler", + "securitySolutionPackages.ecsDataQualityDashboard.changeYourSearchCriteriaOrRun": "Modifiez vos critères de recherche ou lancez une nouvelle vérification", "securitySolutionPackages.ecsDataQualityDashboard.checkAllButton": "Tout vérifier", "securitySolutionPackages.ecsDataQualityDashboard.checkAllErrorCheckingIndexMessage": "Une erreur s'est produite lors de la vérification de l'index {indexName}", "securitySolutionPackages.ecsDataQualityDashboard.checkingLabel": "Vérification de {index}", + "securitySolutionPackages.ecsDataQualityDashboard.checkNow": "Vérifier maintenant", + "securitySolutionPackages.ecsDataQualityDashboard.close": "Fermer", "securitySolutionPackages.ecsDataQualityDashboard.coldDescription": "L'index n'est plus mis à jour et il est interrogé peu fréquemment. Les informations doivent toujours être interrogeables, mais il est acceptable que ces requêtes soient plus lentes.", "securitySolutionPackages.ecsDataQualityDashboard.coldPatternTooltip": "{indices} {indices, plural, =1 {L'index correspondant} other {Les index correspondants}} au modèle {pattern} {indices, plural, =1 {est} other {sont}} \"cold\". Les index \"cold\" ne sont plus mis à jour et ne sont pas interrogés fréquemment. Les informations doivent toujours être interrogeables, mais il est acceptable que ces requêtes soient plus lentes.", "securitySolutionPackages.ecsDataQualityDashboard.compareFieldsTable.searchFieldsPlaceholder": "Rechercher dans les champs", "securitySolutionPackages.ecsDataQualityDashboard.copyToClipboardButton": "Copier dans le presse-papiers", "securitySolutionPackages.ecsDataQualityDashboard.createADataQualityCaseForIndexHeaderText": "Créer un cas de qualité des données pour l'index {indexName}", "securitySolutionPackages.ecsDataQualityDashboard.createADataQualityCaseHeaderText": "Créer un cas de qualité des données", + "securitySolutionPackages.ecsDataQualityDashboard.customFields": "Champs personnalisés", "securitySolutionPackages.ecsDataQualityDashboard.customTab.customFieldsTableTitle": "Champs personnalisés - {indexName}", "securitySolutionPackages.ecsDataQualityDashboard.customTab.ecsComplaintFieldsTableTitle": "Champs de plainte ECS - {indexName}", + "securitySolutionPackages.ecsDataQualityDashboard.dataQuality": "Qualité des données", + "securitySolutionPackages.ecsDataQualityDashboard.dataQualityDashboardConversationId": "Tableau de bord de Qualité des données", "securitySolutionPackages.ecsDataQualityDashboard.dataQualityPromptContextPill": "Qualité des données ({indexName})", "securitySolutionPackages.ecsDataQualityDashboard.dataQualityPromptContextPillTooltip": "Ajoutez ce rapport de Qualité des données comme contexte", "securitySolutionPackages.ecsDataQualityDashboard.dataQualitySuggestedUserPrompt": "Expliquez les résultats ci-dessus et donnez des options pour résoudre les incompatibilités.", "securitySolutionPackages.ecsDataQualityDashboard.defaultPanelTitle": "Vérifier les mappings d'index", + "securitySolutionPackages.ecsDataQualityDashboard.detectionEngineRulesWontWorkMessage": "❌ Les règles de moteur de détection référençant ces champs ne leur correspondront peut-être pas correctement", + "securitySolutionPackages.ecsDataQualityDashboard.docs": "Documents", + "securitySolutionPackages.ecsDataQualityDashboard.documentValuesActual": "Valeurs du document (réelles)", + "securitySolutionPackages.ecsDataQualityDashboard.ecsCompliantFields": "Champs conformes à ECS", + "securitySolutionPackages.ecsDataQualityDashboard.ecsDescription": "Description ECS", + "securitySolutionPackages.ecsDataQualityDashboard.ecsMappingType": "Type de mapping ECS", + "securitySolutionPackages.ecsDataQualityDashboard.ecsMappingTypeExpected": "Type de mapping ECS (attendu)", + "securitySolutionPackages.ecsDataQualityDashboard.ecsValues": "Valeurs ECS", + "securitySolutionPackages.ecsDataQualityDashboard.ecsValuesExpected": "Valeurs ECS (attendues)", "securitySolutionPackages.ecsDataQualityDashboard.ecsVersionStat": "Version ECS", + "securitySolutionPackages.ecsDataQualityDashboard.emptyErrorPrompt.errorGenericCheckTitle": "Une erreur s'est produite durant la vérification", "securitySolutionPackages.ecsDataQualityDashboard.emptyErrorPrompt.errorLoadingMappingsBody": "Un problème est survenu lors du chargement des mappings : {error}", "securitySolutionPackages.ecsDataQualityDashboard.emptyErrorPrompt.errorLoadingMappingsTitle": "Impossible de charger les mappings d'index", "securitySolutionPackages.ecsDataQualityDashboard.emptyErrorPrompt.errorLoadingMetadataTitle": "Les index correspondant au modèle {pattern} ne seront pas vérifiés", "securitySolutionPackages.ecsDataQualityDashboard.emptyErrorPrompt.errorLoadingUnallowedValuesBody": "Un problème est survenu lors du chargement des valeurs non autorisées : {error}", "securitySolutionPackages.ecsDataQualityDashboard.emptyErrorPrompt.errorLoadingUnallowedValuesTitle": "Impossible de charger les valeurs non autorisées", + "securitySolutionPackages.ecsDataQualityDashboard.emptyLoadingPrompt.checkingIndexPrompt": "Vérification de l'index", "securitySolutionPackages.ecsDataQualityDashboard.emptyLoadingPrompt.loadingEcsMetadataPrompt": "Chargement des métadonnées ECS", "securitySolutionPackages.ecsDataQualityDashboard.emptyLoadingPrompt.loadingMappingsPrompt": "Chargement des mappings", "securitySolutionPackages.ecsDataQualityDashboard.emptyLoadingPrompt.loadingStatsPrompt": "Chargement des statistiques", "securitySolutionPackages.ecsDataQualityDashboard.emptyLoadingPrompt.loadingUnallowedValuesPrompt": "Chargement des valeurs non autorisées", + "securitySolutionPackages.ecsDataQualityDashboard.errorLoadingHistoricalResults": "Impossible de charger l'historique", "securitySolutionPackages.ecsDataQualityDashboard.errorLoadingIlmExplainLabel": "Erreur lors du chargement d'ILM Explain : {details}", "securitySolutionPackages.ecsDataQualityDashboard.errorLoadingMappingsLabel": "Erreur lors du chargement des mappings pour {patternOrIndexName} : {details}", "securitySolutionPackages.ecsDataQualityDashboard.errorLoadingStatsLabel": "Erreur lors du chargement des statistiques : {details}", "securitySolutionPackages.ecsDataQualityDashboard.errorLoadingUnallowedValuesLabel": "Erreur lors du chargement des valeurs non autorisées pour l'index {indexName} : {details}", + "securitySolutionPackages.ecsDataQualityDashboard.errors.error": "Erreur", "securitySolutionPackages.ecsDataQualityDashboard.errors.errorMayOccurLabel": "Des erreurs peuvent survenir lorsque le modèle ou les métadonnées de l'index sont temporairement indisponibles, ou si vous ne disposez pas des privilèges requis pour l'accès", + "securitySolutionPackages.ecsDataQualityDashboard.errors.errors": "Erreurs", + "securitySolutionPackages.ecsDataQualityDashboard.errors.errorsCalloutSummary": "La qualité des données n'a pas été vérifiée pour certains index", "securitySolutionPackages.ecsDataQualityDashboard.errors.manage": "gérer", "securitySolutionPackages.ecsDataQualityDashboard.errors.monitor": "moniteur", "securitySolutionPackages.ecsDataQualityDashboard.errors.or": "ou", + "securitySolutionPackages.ecsDataQualityDashboard.errors.pattern": "Modèle", "securitySolutionPackages.ecsDataQualityDashboard.errors.read": "lire", "securitySolutionPackages.ecsDataQualityDashboard.errors.theFollowingPrivilegesLabel": "Les privilèges suivants sont requis pour vérifier un index :", "securitySolutionPackages.ecsDataQualityDashboard.errors.viewIndexMetadata": "view_index_metadata", "securitySolutionPackages.ecsDataQualityDashboard.errorsPopover.viewErrorsButton": "Afficher les erreurs", + "securitySolutionPackages.ecsDataQualityDashboard.fail": "Échec", + "securitySolutionPackages.ecsDataQualityDashboard.failedTooltip": "Échoué", + "securitySolutionPackages.ecsDataQualityDashboard.field": "Champ", "securitySolutionPackages.ecsDataQualityDashboard.fieldsLabel": "Champs", + "securitySolutionPackages.ecsDataQualityDashboard.filterResultsByOutcome": "Filtrer les résultats par issue", "securitySolutionPackages.ecsDataQualityDashboard.frozenDescription": "L'index n'est plus mis à jour et il est rarement interrogé. Les informations doivent toujours être interrogeables, mais il est acceptable que ces requêtes soient extrêmement lentes.", "securitySolutionPackages.ecsDataQualityDashboard.frozenPatternTooltip": "{indices} {indices, plural, =1 {L'index correspondant} other {Les index correspondants}} au modèle {pattern} {indices, plural, =1 {est} other {sont}} \"frozen\". Les index gelés ne sont plus mis à jour et sont rarement interrogés. Les informations doivent toujours être interrogeables, mais il est acceptable que ces requêtes soient extrêmement lentes.", "securitySolutionPackages.ecsDataQualityDashboard.getResultErrorTitle": "Erreur lors de la lecture des résultats d'examen qualité des données sauvegardées", "securitySolutionPackages.ecsDataQualityDashboard.hotDescription": "L'index est mis à jour et interrogé de façon active", "securitySolutionPackages.ecsDataQualityDashboard.hotPatternTooltip": "{indices} {indices, plural, =1 {L'index correspondant} other {Les index correspondants}} au modèle {pattern} {indices, plural, =1 {est} other {sont}} \"hot\". Les index \"hot\" sont mis à jour et interrogés de façon active.", + "securitySolutionPackages.ecsDataQualityDashboard.ilmPhaseCapitalized": "Phase ILM", "securitySolutionPackages.ecsDataQualityDashboard.ilmPhaseCold": "froid", "securitySolutionPackages.ecsDataQualityDashboard.ilmPhaseFrozen": "frozen", "securitySolutionPackages.ecsDataQualityDashboard.ilmPhaseHot": "hot", @@ -6943,7 +7621,20 @@ "securitySolutionPackages.ecsDataQualityDashboard.ilmPhasesEmptyPromptTitle": "Sélectionner une ou plusieurs phases ILM", "securitySolutionPackages.ecsDataQualityDashboard.ilmPhaseUnmanaged": "non géré", "securitySolutionPackages.ecsDataQualityDashboard.ilmPhaseWarm": "warm", + "securitySolutionPackages.ecsDataQualityDashboard.incompatibleCallout": "Les champs sont incompatibles avec ECS lorsque les mappings d'index, ou les valeurs des champs de l'index, ne sont pas conformes à la version {version} d'Elastic Common Schema (ECS).", + "securitySolutionPackages.ecsDataQualityDashboard.incompatibleCalloutTitle": "{fieldCount} {fieldCount, plural, =1 {Champ incompatible} other {Champs incompatibles}}", + "securitySolutionPackages.ecsDataQualityDashboard.incompatibleEmptyContent": "Tous les mappings de champs et toutes les valeurs de documents de cet index sont conformes à Elastic Common Schema (ECS).", + "securitySolutionPackages.ecsDataQualityDashboard.incompatibleEmptyTitle": "Toutes les valeurs et tous les mappings de champs sont conformes à ECS", + "securitySolutionPackages.ecsDataQualityDashboard.incompatibleFieldMappings": "Mappings de champ incompatibles – {indexName}", + "securitySolutionPackages.ecsDataQualityDashboard.incompatibleFields": "Champs incompatibles", + "securitySolutionPackages.ecsDataQualityDashboard.incompatibleFieldsWithCount": "{count, plural, one {Champ incompatible} other {Champs incompatibles}}", + "securitySolutionPackages.ecsDataQualityDashboard.incompatibleFieldValues": "Valeurs de champ incompatibles – {indexName}", + "securitySolutionPackages.ecsDataQualityDashboard.index": "Index", + "securitySolutionPackages.ecsDataQualityDashboard.indexCheckFlyout.historyTab": "Historique", + "securitySolutionPackages.ecsDataQualityDashboard.indexCheckFlyout.latestCheckTab": "Dernière vérification", "securitySolutionPackages.ecsDataQualityDashboard.indexLifecycleManagementPhasesTooltip": "La qualité des données sera vérifiée pour les index comprenant ces phases de gestion du cycle de vie des index (ILM, Index Lifecycle Management)", + "securitySolutionPackages.ecsDataQualityDashboard.indexMappingType": "Type de mapping d'index", + "securitySolutionPackages.ecsDataQualityDashboard.indexMappingTypeActual": "Type de mapping d'index (réel)", "securitySolutionPackages.ecsDataQualityDashboard.indexNameLabel": "Nom de l'index", "securitySolutionPackages.ecsDataQualityDashboard.indexProperties.addToNewCaseButton": "Ajouter au nouveau cas", "securitySolutionPackages.ecsDataQualityDashboard.indexProperties.allCallout": "Tous les mappings relatifs aux champs de cet index, y compris ceux qui sont conformes à la version {version} d'Elastic Common Schema (ECS) et ceux qui ne le sont pas", @@ -6979,47 +7670,81 @@ "securitySolutionPackages.ecsDataQualityDashboard.indexProperties.summaryMarkdownDescription": "L'index `{indexName}` a des [mappings]({mappingUrl}) ou des valeurs de champ différentes de l'[Elastic Common Schema]({ecsReferenceUrl}) (ECS), [définitions]({ecsFieldReferenceUrl}).de version `{version}`.", "securitySolutionPackages.ecsDataQualityDashboard.indexProperties.summaryMarkdownTitle": "Qualité des données", "securitySolutionPackages.ecsDataQualityDashboard.indexProperties.unknownCategoryLabel": "Inconnu", - "securitySolutionPackages.ecsDataQualityDashboard.indexSizeTooltip": "La taille de l'index principal (n'inclut pas de répliques)", + "securitySolutionPackages.ecsDataQualityDashboard.indexSizeTooltip": "Taille de l'index (sans les répliques)", + "securitySolutionPackages.ecsDataQualityDashboard.indices": "Index", + "securitySolutionPackages.ecsDataQualityDashboard.indicesChecked": "Index vérifiés", + "securitySolutionPackages.ecsDataQualityDashboard.introducingDataQualityHistory": "Présentation de l'historique de la qualité des données", "securitySolutionPackages.ecsDataQualityDashboard.lastCheckedLabel": "Dernière vérification", + "securitySolutionPackages.ecsDataQualityDashboard.loadingHistoricalResults": "Chargement des résultats antérieurs", + "securitySolutionPackages.ecsDataQualityDashboard.mappingThatConflictWithEcsMessage": "❌ Les mappings ou valeurs de champs qui ne sont pas conformes à ECS ne sont pas pris en charge", + "securitySolutionPackages.ecsDataQualityDashboard.noResultsMatchYourSearchCriteria": "Aucun résultat ne correspond à vos critères de recherche.", + "securitySolutionPackages.ecsDataQualityDashboard.notIncludedInHistoricalResults": "Non inclus dans les résultats antérieurs. Pour afficher les données complètes sur les champs de la même famille, exécutez une nouvelle vérification.", + "securitySolutionPackages.ecsDataQualityDashboard.pagesMayNotDisplayEventsMessage": "❌ Les pages peuvent ne pas afficher certains événements ou champs en raison de mappings ou valeurs de champs inattendus", + "securitySolutionPackages.ecsDataQualityDashboard.pass": "Réussite", + "securitySolutionPackages.ecsDataQualityDashboard.passedTooltip": "Approuvé", "securitySolutionPackages.ecsDataQualityDashboard.patternLabel.allPassedTooltip": "Tous les index correspondant à ce modèle ont réussi les vérifications de qualité des données", + "securitySolutionPackages.ecsDataQualityDashboard.patternLabel.someFailedTooltip": "Au moins un index correspondant à ce modèle a échoué à un contrôle de qualité des données", + "securitySolutionPackages.ecsDataQualityDashboard.patternLabel.someUncheckedTooltip": "Au moins un index correspondant à ce modèle n'a pas été vérifié pour la qualité des données", "securitySolutionPackages.ecsDataQualityDashboard.patternSummary.docsLabel": "Documents", "securitySolutionPackages.ecsDataQualityDashboard.patternSummary.indicesLabel": "Index", - "securitySolutionPackages.ecsDataQualityDashboard.patternSummary.patternOrIndexTooltip": "Modèle, ou index spécifique", + "securitySolutionPackages.ecsDataQualityDashboard.patternSummary.patternOrIndexTooltip": "Nom d'index ou modèle", "securitySolutionPackages.ecsDataQualityDashboard.postResultErrorTitle": "Erreur lors de l'écriture des résultats d'examen qualité des données sauvegardées", "securitySolutionPackages.ecsDataQualityDashboard.remoteClustersCallout.title": "Les clusters distants ne seront pas vérifiés", "securitySolutionPackages.ecsDataQualityDashboard.remoteClustersCallout.toCheckIndicesOnRemoteClustersLabel": "Pour vérifier les index sur des clusters distants prenant en charge la recherche dans différents clusters, connectez-vous à l'instance Kibana du cluster distant", + "securitySolutionPackages.ecsDataQualityDashboard.result": "Résultat", + "securitySolutionPackages.ecsDataQualityDashboard.sameFamily": "Même famille", "securitySolutionPackages.ecsDataQualityDashboard.sameFamilyBadgeLabel": "même famille", "securitySolutionPackages.ecsDataQualityDashboard.sameFamilyTab.sameFamilyFieldMappingsTableTitle": "Mêmes familles de mappings de champ – {indexName}", "securitySolutionPackages.ecsDataQualityDashboard.securitySolutionPackages.ecsDataQualityDashboardSubtitle": "Vérifiez la compatibilité des mappings et des valeurs d'index avec", "securitySolutionPackages.ecsDataQualityDashboard.selectAnIndexPrompt": "Sélectionner un index pour le comparer à la version ECS", "securitySolutionPackages.ecsDataQualityDashboard.selectOneOrMorPhasesPlaceholder": "Sélectionner une ou plusieurs phases ILM", + "securitySolutionPackages.ecsDataQualityDashboard.size": "Taille", "securitySolutionPackages.ecsDataQualityDashboard.statLabels.checkedLabel": "vérifié", "securitySolutionPackages.ecsDataQualityDashboard.statLabels.docsLabel": "Documents", + "securitySolutionPackages.ecsDataQualityDashboard.statLabels.incompatibleFieldsLabel": "Champs incompatibles", + "securitySolutionPackages.ecsDataQualityDashboard.statLabels.incompatibleIndexToolTip": "Mappings et valeurs incompatibles avec ECS", + "securitySolutionPackages.ecsDataQualityDashboard.statLabels.indicesCheckedLabel": "Index vérifiés", "securitySolutionPackages.ecsDataQualityDashboard.statLabels.indicesLabel": "Index", "securitySolutionPackages.ecsDataQualityDashboard.statLabels.sameFamilyLabel": "Même famille", "securitySolutionPackages.ecsDataQualityDashboard.statLabels.sizeLabel": "Taille", - "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalDocsToolTip": "Nombre total de documents, dans tous les index", - "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalIncompatibleToolTip": "Nombre total de champs incompatibles avec ECS, dans tous les index qui ont été vérifiés", - "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalIndicesToolTip": "Nombre total de tous les index", - "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalSizeToolTip": "La taille totale de tous les index principaux (n'inclut pas de répliques)", + "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalCheckedIndicesPatternToolTip": "Nombre total d'index vérifiés correspondant à ce modèle d'index", + "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalCheckedIndicesToolTip": "Nombre total d'index vérifiés", + "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalDocsPatternToolTip": "Nombre total de documents dans les index correspondant à ce modèle d'indexation", + "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalDocsToolTip": "Nombre total de documents dans l'ensemble des index", + "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalIncompatiblePatternToolTip": "Nombre total de champs vérifiés incompatibles avec ECS dans les index correspondant à ce modèle d'indexation", + "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalIncompatibleToolTip": "Nombre total de champs vérifiés incompatibles avec ECS", + "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalIndicesPatternToolTip": "Nombre total d'index correspondant à ce modèle d'indexation", + "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalIndicesToolTip": "Nombre total d'index", + "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalSizePatternToolTip": "Taille totale des indices (hors répliques) correspondant à ce modèle d'indexation", + "securitySolutionPackages.ecsDataQualityDashboard.statLabels.totalSizeToolTip": "Taille totale des indices (hors répliques)", "securitySolutionPackages.ecsDataQualityDashboard.storage.docs.unit": "{totalCount, plural, =1 {Document} other {Documents}}", "securitySolutionPackages.ecsDataQualityDashboard.storageTreemap.noDataLabel": "Aucune donnée à afficher", "securitySolutionPackages.ecsDataQualityDashboard.storageTreemap.noDataReasonLabel": "Le champ {stackByField1} n'était présent dans aucun groupe", + "securitySolutionPackages.ecsDataQualityDashboard.summaryTable.actionsColumn": "Actions", "securitySolutionPackages.ecsDataQualityDashboard.summaryTable.collapseLabel": "Réduire", "securitySolutionPackages.ecsDataQualityDashboard.summaryTable.expandRowsColumn": "Développer les lignes", "securitySolutionPackages.ecsDataQualityDashboard.summaryTable.indexesNameLabel": "Nom de l'index", "securitySolutionPackages.ecsDataQualityDashboard.summaryTable.indexToolTip": "Cet index correspond au nom d'index ou de modèle : {pattern}", "securitySolutionPackages.ecsDataQualityDashboard.summaryTable.lastCheckColumn": "Dernière vérification", + "securitySolutionPackages.ecsDataQualityDashboard.thisIndexHasNotBeenCheckedTooltip": "Cet index n'a pas été vérifié", "securitySolutionPackages.ecsDataQualityDashboard.timestampDescriptionLabel": "Date/heure d'origine de l'événement. Il s'agit des date et heure extraites de l'événement, représentant généralement le moment auquel l'événement a été généré par la source. Si la source de l'événement ne comporte pas d'horodatage original, cette valeur est habituellement remplie la première fois que l'événement a été reçu par le pipeline. Champs requis pour tous les événements.", "securitySolutionPackages.ecsDataQualityDashboard.toasts.copiedErrorsToastTitle": "Erreurs copiées dans le presse-papiers", "securitySolutionPackages.ecsDataQualityDashboard.toasts.copiedResultsToastTitle": "Résultats copiés dans le presse-papiers", + "securitySolutionPackages.ecsDataQualityDashboard.toggleHistoricalResultCheckedAt": "Bascule de résultat historique vérifié à {checkedAt}", + "securitySolutionPackages.ecsDataQualityDashboard.totalChecks": "{formattedCount} {count, plural, one {vérification} other {vérifications}}", + "securitySolutionPackages.ecsDataQualityDashboard.tryIt": "Essayer", "securitySolutionPackages.ecsDataQualityDashboard.unmanagedDescription": "L'index n'est pas géré par la Gestion du cycle de vie des index (ILM)", "securitySolutionPackages.ecsDataQualityDashboard.unmanagedPatternTooltip": "{indices} {indices, plural, =1 {L'index correspondant} other {Les index correspondants}} au modèle {pattern} {indices, plural, =1 {n'est pas géré} other {ne sont pas gérés}} par la gestion du cycle de vie des index (ILM)", + "securitySolutionPackages.ecsDataQualityDashboard.viewHistory": "Afficher l'historique", + "securitySolutionPackages.ecsDataQualityDashboard.viewPastResults": "Voir les résultats antérieurs", "securitySolutionPackages.ecsDataQualityDashboard.warmDescription": "L'index n'est plus mis à jour mais il est toujours interrogé", "securitySolutionPackages.ecsDataQualityDashboard.warmPatternTooltip": "{indices} {indices, plural, =1 {L'index correspondant} other {Les index correspondants}} au modèle {pattern} {indices, plural, =1 {est} other {sont}} \"warm\". Les index \"warm\" ne sont plus mis à jour, mais ils sont toujours interrogés.", "securitySolutionPackages.entityAnalytics.navigation": "Analyse des entités", "securitySolutionPackages.entityAnalytics.pageDesc": "Détecter les menaces des utilisateurs et des hôtes de votre réseau avec l'Analyse des entités", "securitySolutionPackages.entityAnalytics.paywall.upgradeButton": "Passer à {requiredLicenseOrProduct}", + "securitySolutionPackages.features.featureRegistry.assistant.manageGlobalKnowledgeBaseSubFeatureDescription": "Apportez des modifications à n'importe quelle entrée de la base de connaissances personnalisée au niveau de l'espace (global). Cela permettra également aux utilisateurs de modifier les entrées globales créées par d'autres utilisateurs.", + "securitySolutionPackages.features.featureRegistry.assistant.manageGlobalKnowledgeBaseSubFeatureDetails": "Autoriser les modifications des entrées globales", + "securitySolutionPackages.features.featureRegistry.assistant.manageGlobalKnowledgeBaseSubFeatureName": "Base de connaissances", "securitySolutionPackages.features.featureRegistry.assistant.updateAnonymizationSubFeatureDetails": "Autoriser les modifications", "securitySolutionPackages.features.featureRegistry.assistant.updateAnonymizationSubFeatureName": "Sélection et Anonymisation de champ", "securitySolutionPackages.features.featureRegistry.casesSettingsSubFeatureDetails": "Modifier les paramètres du cas", @@ -7027,8 +7752,10 @@ "securitySolutionPackages.features.featureRegistry.deleteSubFeatureDetails": "Supprimer les cas et les commentaires", "securitySolutionPackages.features.featureRegistry.deleteSubFeatureName": "Supprimer", "securitySolutionPackages.features.featureRegistry.linkSecuritySolutionAssistantTitle": "Assistant d’intelligence artificielle d’Elastic", + "securitySolutionPackages.features.featureRegistry.linkSecuritySolutionAttackDiscoveryTitle": "Attack discovery", "securitySolutionPackages.features.featureRegistry.linkSecuritySolutionCaseTitle": "Cas", "securitySolutionPackages.features.featureRegistry.linkSecuritySolutionTitle": "Sécurité", + "securitySolutionPackages.features.featureRegistry.securityGroupDescription": "Chaque privilège de sous-fonctionnalité de ce groupe doit être attribué individuellement. L'affectation globale n'est prise en charge que lorsque votre offre tarifaire n'autorise pas les privilèges de fonctionnalités individuelles.", "securitySolutionPackages.features.featureRegistry.subFeatures.assistant.description": "Modifiez les champs par défaut autorisés à être utilisés par l'assistant IA et Attack discovery. Anonymisez n'importe quel contenu pour les champs sélectionnés.", "securitySolutionPackages.features.featureRegistry.subFeatures.blockList": "Liste noire", "securitySolutionPackages.features.featureRegistry.subFeatures.blockList.description": "Étendez la protection d'Elastic Defend contre les processus malveillants et protégez-vous des applications potentiellement nuisibles.", @@ -7074,6 +7801,10 @@ "securitySolutionPackages.navigation.landingLinks": "Vues de sécurité", "securitySolutionPackages.sideNav.betaBadge.label": "Bêta", "securitySolutionPackages.sideNav.togglePanel": "Activer/Désactiver le panneau de navigation", + "securitySolutionPackages.upselling.pages.attackDiscovery.pageTitle.betaBadge": "Version d'évaluation technique", + "securitySolutionPackages.upselling.pages.attackDiscovery.pageTitle.betaTooltip": "Cette fonctionnalité est en version d’évaluation technique, elle est susceptible d’être modifiée. Veuillez utiliser Attack Discovery avec prudence dans les environnements de production.", + "securitySolutionPackages.upselling.pages.attackDiscovery.pageTitle.pageTitle": "Attack discovery", + "securitySolutionPackages.upselling.sections.attackDiscovery.findPotentialAttacksWithAiTitle": "Trouvez les attaques potentielles grâce à l'IA", "share.advancedSettings.csv.quoteValuesText": "Les valeurs doivent-elles être mises entre guillemets dans les exportations CSV ?", "share.advancedSettings.csv.quoteValuesTitle": "Mettre les valeurs CSV entre guillemets", "share.advancedSettings.csv.separatorText": "Séparer les valeurs exportées avec cette chaîne", @@ -7089,8 +7820,6 @@ "share.dashboard.link.description": "Partagez un lien direct avec cette recherche.", "share.embed.dashboard.helpText": "Intégrez ce tableau de bord dans une autre page web. Sélectionnez les éléments à inclure dans la vue intégrable.", "share.embed.helpText": "Intégrez ce {objectType} dans une autre page web.", - "share.export.generateButtonLabel": "Exporter un fichier", - "share.export.helpText": "Sélectionnez le type de fichier que vous souhaitez exporter pour cette visualisation.", "share.fileType": "Type de fichier", "share.link.copied": "Texte copié", "share.link.copyEmbedCodeButton": "Copier le code intégré", @@ -7101,7 +7830,7 @@ "share.modalContent.copyUrlButtonLabel": "Copier l'URL Post", "share.postURLWatcherMessage": "Copiez cette URL POST pour appeler la génération depuis l'extérieur de Kibana ou à partir de Watcher.", "share.postURLWatcherMessage.unsavedChanges": "L'URL peut changer si vous mettez Kibana à niveau.", - "share.screenCapturePanelContent.optimizeForPrintingHelpText": "Utilise plusieurs pages, affichant au maximum 2 visualisations par page ", + "share.screenCapturePanelContent.optimizeForPrintingHelpText": "Utilise plusieurs pages, affichant au maximum 2 visualisations par page", "share.screenCapturePanelContent.optimizeForPrintingLabel": "Pour l'impression", "share.urlPanel.canNotShareAsSavedObjectHelpText": "Pour le partager comme objet enregistré, enregistrez le {objectType}.", "share.urlPanel.copyIframeCodeButtonLabel": "Copier le code iFrame", @@ -7134,6 +7863,8 @@ "sharedUXPackages.card.noData.noPermission.title": "Contactez votre administrateur", "sharedUXPackages.card.noData.title": "Ajouter Elastic Agent", "sharedUXPackages.chrome.sideNavigation.betaBadge.label": "Bêta", + "sharedUXPackages.chrome.sideNavigation.feedbackCallout.btn": "Faites-nous en part", + "sharedUXPackages.chrome.sideNavigation.feedbackCallout.title": "Comment fonctionne la navigation de votre côté ? Il manque quelque chose ?", "sharedUXPackages.chrome.sideNavigation.recentlyAccessed.title": "Récent", "sharedUXPackages.chrome.sideNavigation.togglePanel": "Afficher/Masquer le panneau de navigation \"{title}\"", "sharedUXPackages.codeEditor.ariaLabel": "Éditeur de code", @@ -7201,11 +7932,17 @@ "sharedUXPackages.noDataPage.introNoDocLink": "Ajoutez vos données pour commencer.", "sharedUXPackages.noDataPage.welcomeTitle": "Bienvenue dans Elastic {solution}.", "sharedUXPackages.noDataViewsPrompt.addDataViewText": "Créer une vue de données", + "sharedUXPackages.noDataViewsPrompt.addDataViewTextNoPrivilege": "Créer une vue de données", + "sharedUXPackages.noDataViewsPrompt.addDataViewTooltipNoPrivilege": "Demandez à votre administrateur les autorisations nécessaires pour créer une vue de données.", + "sharedUXPackages.noDataViewsPrompt.createDataView": "Créer une vue de données", "sharedUXPackages.noDataViewsPrompt.dataViewExplanation": "Les vues de données identifient les données Elasticsearch que vous souhaitez explorer. Vous pouvez faire pointer des vues de données vers un ou plusieurs flux de données, index et alias d'index, tels que vos données de log d'hier, ou vers tous les index contenant vos données de log.", + "sharedUXPackages.noDataViewsPrompt.esqlExplanation": "ES|QL est un langage de requête canalisé de nouvelle génération et un moteur de calcul développé par Elastic pour filtrer, transformer et analyser les données. ES|QL vous aide à rationaliser vos workflows afin d'assurer un traitement des données rapide et efficace.", + "sharedUXPackages.noDataViewsPrompt.esqlPanel.title": "Interrogez vos données avec ES|QL", "sharedUXPackages.noDataViewsPrompt.learnMore": "Envie d'en savoir plus ?", "sharedUXPackages.noDataViewsPrompt.noPermission.dataViewExplanation": "Les vues de données identifient les données Elasticsearch que vous souhaitez explorer. Pour créer des vues de données, demandez les autorisations requises à votre administrateur.", "sharedUXPackages.noDataViewsPrompt.readDocumentation": "Lisez les documents", - "sharedUXPackages.noDataViewsPrompt.youHaveData": "Vous avez des données dans Elasticsearch.", + "sharedUXPackages.noDataViewsPrompt.tryEsqlText": "Essayer ES|QL", + "sharedUXPackages.noDataViewsPrompt.youHaveData": "Comment souhaitez-vous explorer vos données Elasticsearch ?", "sharedUXPackages.prompt.errors.notFound.body": "Désolé, la page que vous recherchez est introuvable. Elle a peut-être été retirée ou renommée, ou peut-être qu'elle n'a jamais existé.", "sharedUXPackages.prompt.errors.notFound.goBacklabel": "Retour", "sharedUXPackages.prompt.errors.notFound.title": "Page introuvable", @@ -7213,6 +7950,7 @@ "sharedUXPackages.solutionNav.menuText": "menu", "sharedUXPackages.solutionNav.mobileTitleText": "{solutionName} {menuText}", "sharedUXPackages.solutionNav.openLabel": "Ouvrir la navigation latérale", + "sse.internalError": "Une erreur interne s'est produite", "telemetry.callout.appliesSettingTitle": "Les modifications apportées à ce paramètre s'appliquent dans {allOfKibanaText} et sont enregistrées automatiquement.", "telemetry.callout.appliesSettingTitle.allOfKibanaText": "tout Kibana", "telemetry.callout.clusterStatisticsDescription": "Voici un exemple des statistiques de cluster de base que nous collecterons. Cela comprend le nombre d'index, de partitions et de nœuds. Cela comprend également des statistiques d'utilisation de niveau élevé, comme l'état d'activation du monitoring.", @@ -7290,12 +8028,12 @@ "timelion.help.functions.fitHelpText": "Remplit les valeurs nulles à l'aide d'une fonction fit définie.", "timelion.help.functions.hide.args.hideHelpText": "Masquer ou afficher les séries", "timelion.help.functions.hideHelpText": "Masquer les séries par défaut", - "timelion.help.functions.holt.args.alphaHelpText": "\n Pondération de lissage de 0 à 1.\n Augmentez l’alpha pour que la nouvelle série suive de plus près l'originale.\n Diminuez-le pour rendre la série plus lisse.", - "timelion.help.functions.holt.args.betaHelpText": "\n Pondération de tendance de 0 à 1.\n Augmentez le bêta pour que les lignes montantes/descendantes continuent à monter/descendre plus longtemps.\n Diminuez-le pour que la fonction apprenne plus rapidement la nouvelle tendance.", - "timelion.help.functions.holt.args.gammaHelpText": "\n Pondération saisonnière de 0 à 1. Vos données ressemblent-elles à une vague ?\n Augmentez cette valeur pour donner plus d'importance aux saisons récentes et ainsi modifier plus rapidement la forme de la vague.\n Diminuez-la pour réduire l'importance des nouvelles saisons et ainsi rendre l'historique plus important.\n ", - "timelion.help.functions.holt.args.sampleHelpText": "\n Le nombre de saisons à échantillonner avant de commencer à \"prédire\" dans une série saisonnière.\n (Utile uniquement avec gamma, par défaut : all)", + "timelion.help.functions.holt.args.alphaHelpText": "Pondération de lissage de 0 à 1. Augmentez l’alpha pour que la nouvelle série suive de plus près l'originale. Diminuez-le pour rendre la série plus lisse.", + "timelion.help.functions.holt.args.betaHelpText": "Pondération de tendance de 0 à 1. Augmentez le bêta pour que les lignes montantes/descendantes continuent à monter/descendre plus longtemps. Diminuez-le pour que la fonction apprenne plus rapidement la nouvelle tendance.", + "timelion.help.functions.holt.args.gammaHelpText": "Pondération saisonnière de 0 à 1. Vos données ressemblent-elles à une vague ? Augmentez cette valeur pour donner plus d'importance aux saisons récentes et ainsi modifier plus rapidement la forme de la vague. Diminuez-la pour réduire l'importance des nouvelles saisons et ainsi rendre l'historique plus important.", + "timelion.help.functions.holt.args.sampleHelpText": "Le nombre de saisons à échantillonner avant de commencer à \"prédire\" dans une série saisonnière. (Utile uniquement avec gamma, par défaut : all)", "timelion.help.functions.holt.args.seasonHelpText": "La longueur de la saison, par ex. 1w, si votre modèle se répète chaque semaine. (Utile uniquement avec gamma)", - "timelion.help.functions.holtHelpText": "\n Échantillonner le début d'une série et l'utiliser pour prévoir ce qui devrait se produire\n via plusieurs paramètres facultatifs. En règle générale, cela ne prédit pas\n l'avenir, mais ce qui devrait se produire maintenant en fonction des données passées,\n ce qui peut être utile pour la détection des anomalies. Notez que les valeurs null seront remplacées par des valeurs prévues.", + "timelion.help.functions.holtHelpText": "Échantillonner le début d'une série et l'utiliser pour prévoir ce qui devrait se produire via plusieurs paramètres facultatifs. En règle générale, cela ne prédit pas l'avenir, mais ce qui devrait se produire maintenant en fonction des données passées, ce qui peut être utile pour la détection des anomalies. Notez que les valeurs null seront remplacées par des valeurs prévues.", "timelion.help.functions.label.args.labelHelpText": "Valeur de légende pour les séries. Vous pouvez utiliser $1, $2, etc. dans la chaîne pour correspondre aux groupes de captures d'expressions régulières.", "timelion.help.functions.label.args.regexHelpText": "Une expression régulière compatible avec les groupes de captures", "timelion.help.functions.labelHelpText": "Modifiez l'étiquette des séries. Utiliser %s pour référencer l'étiquette existante", @@ -7362,10 +8100,10 @@ "timelion.help.functions.trim.args.startHelpText": "Compartiments à retirer du début de la série. Par défaut : 1", "timelion.help.functions.trimHelpText": "Définir N compartiments au début ou à la fin de la série sur null pour ajuster le \"problème de compartiment partiel\"", "timelion.help.functions.worldbank.args.codeHelpText": "Chemin de l'API Worldbank (Banque mondiale). Il s'agit généralement de tout ce qui suit le domaine, avant la chaîne de requête. Par exemple : {apiPathExample}.", - "timelion.help.functions.worldbankHelpText": "\n [expérimental]\n Extrayez des données de {worldbankUrl} à l'aide du chemin d’accès aux séries.\n La Banque mondiale fournit surtout des données annuelles et n'a souvent aucune donnée pour l'année en cours.\n Essayez {offsetQuery} si vous n’obtenez pas de données pour les plages temporelles récentes.", + "timelion.help.functions.worldbankHelpText": "[expérimental] Extrayez des données de {worldbankUrl} à l'aide du chemin d’accès aux séries. La Banque mondiale fournit surtout des données annuelles et n'a souvent aucune donnée pour l'année en cours. Essayez {offsetQuery} si vous n’obtenez pas de données pour les plages temporelles récentes.", "timelion.help.functions.worldbankIndicators.args.countryHelpText": "Identifiant de pays de la Banque mondiale. Généralement le code à 2 caractères du pays.", "timelion.help.functions.worldbankIndicators.args.indicatorHelpText": "Le code d'indicateur à utiliser. Vous devrez le rechercher sur {worldbankUrl}. Souvent très complexe. Par exemple, {indicatorExample} correspond à la population.", - "timelion.help.functions.worldbankIndicatorsHelpText": "\n [expérimental]\n Extrayez des données de {worldbankUrl} à l'aide du nom et de l'indicateur du pays. La Banque mondiale fournit\n surtout des données annuelles et n'a souvent aucune donnée pour l'année en cours. Essayez {offsetQuery} si vous n’obtenez pas de données pour\n les plages temporelles récentes.", + "timelion.help.functions.worldbankIndicatorsHelpText": "[expérimental] Extrayez des données de {worldbankUrl} à l'aide du nom et de l'indicateur du pays. La Banque mondiale fournit surtout des données annuelles et n'a souvent aucune donnée pour l'année en cours. Essayez {offsetQuery} si vous n’obtenez pas de données pour les plages temporelles récentes.", "timelion.help.functions.yaxis.args.colorHelpText": "Couleur de l'étiquette de l'axe", "timelion.help.functions.yaxis.args.labelHelpText": "Étiquette de l'axe", "timelion.help.functions.yaxis.args.maxHelpText": "Valeur max.", @@ -7420,6 +8158,9 @@ "timelion.vis.invalidIntervalErrorMessage": "Format d'intervalle non valide.", "timelion.vis.selectIntervalHelpText": "Choisissez une option ou créez une valeur personnalisée. Exemples : 30s, 20m, 24h, 2d, 1w, 1M", "timelion.vis.selectIntervalPlaceholder": "Choisir un intervalle", + "tryInConsole.button.text": "Exécuter dans la console", + "tryInConsole.embeddedConsoleButton.ariaLabel": "Exécuter dans la console - s'ouvre dans la console intégrée", + "tryInConsole.inNewTab.button.ariaLabel": "Exécuter dans la console - s'ouvre dans un nouvel onglet", "uiActions.actionPanel.more": "Plus", "uiActions.actionPanel.title": "Options", "uiActions.errors.incompatibleAction": "Action non compatible", @@ -7498,10 +8239,11 @@ "uiActionsEnhanced.drilldowns.urlDrilldownCollectConfig.urlTemplateSyntaxHelpLinkText": "Aide pour la syntaxe", "uiActionsEnhanced.drilldowns.urlDrilldownCollectConfig.urlTemplateVariablesFilterPlaceholderText": "Variables de filtre", "uiActionsEnhanced.drilldowns.urlDrilldownCollectConfig.urlTemplateVariablesHelpLinkText": "Aide", - "uiActionsEnhanced.drilldowns.urlDrilldownValidation.urlFormatGeneralErrorMessage": "Format non valide.", + "unifiedDataTable.additionalActionsColumnHeader": "Colonne d'actions supplémentaires", "unifiedDataTable.advancedDiffModesTooltip": "Les modes avancés offrent des capacités de diffraction améliorées, mais ils fonctionnent sur des documents bruts et ne prennent donc pas en charge le formatage des champs.", "unifiedDataTable.clearSelection": "Effacer la sélection", - "unifiedDataTable.compareSelectedRowsButtonLabel": "Comparer", + "unifiedDataTable.compareSelectedRowsButtonDisabledTooltip": "La comparaison est limitée à {limit} lignes", + "unifiedDataTable.compareSelectedRowsButtonLabel": "Comparer les éléments sélectionnés", "unifiedDataTable.comparingDocuments": "Comparaison de {documentCount} documents", "unifiedDataTable.comparingResults": "Comparaison de {documentCount} résultats", "unifiedDataTable.comparisonColumnPinnedTooltip": "Document épinglé : {documentId}", @@ -7514,10 +8256,15 @@ "unifiedDataTable.controlColumnHeader": "Colonne de commande", "unifiedDataTable.copyColumnNameToClipboard.toastTitle": "Copié dans le presse-papiers", "unifiedDataTable.copyColumnValuesToClipboard.toastTitle": "Valeurs de la colonne \"{column}\" copiées dans le presse-papiers", + "unifiedDataTable.copyDocsToClipboardJSON": "Copier des documents au format JSON", "unifiedDataTable.copyEscapedValueWithFormulasToClipboardWarningText": "Les valeurs peuvent contenir des formules avec échappement.", "unifiedDataTable.copyFailedErrorText": "Impossible de copier dans le presse-papiers avec ce navigateur", - "unifiedDataTable.copyResultsToClipboardJSON": "Copier les résultats dans le presse-papiers (JSON)", + "unifiedDataTable.copyResultsToClipboardJSON": "Copier les résultats au format JSON", + "unifiedDataTable.copyRowsAsJsonToClipboard.toastTitle": "Copié dans le presse-papiers", + "unifiedDataTable.copyRowsAsTextToClipboard.toastTitle": "Copié dans le presse-papiers", + "unifiedDataTable.copySelectionToClipboard": "Copier la sélection en tant que texte", "unifiedDataTable.copyValueToClipboard.toastTitle": "Copié dans le presse-papiers", + "unifiedDataTable.deselectAllRowsOnPageColumnHeader": "Désélectionner toutes les lignes visibles", "unifiedDataTable.diffModeChars": "Par caractère", "unifiedDataTable.diffModeFullValue": "Valeur totale", "unifiedDataTable.diffModeLines": "Par ligne", @@ -7528,17 +8275,20 @@ "unifiedDataTable.enableShowDiff": "Vous devez activer l'option Afficher les différences", "unifiedDataTable.exitDocumentComparison": "Quitter le mode comparaison", "unifiedDataTable.fieldColumnTitle": "Champ", + "unifiedDataTable.grid.additionalRowActions": "Actions supplémentaires", "unifiedDataTable.grid.closePopover": "Fermer la fenêtre contextuelle", "unifiedDataTable.grid.copyCellValueButton": "Copier la valeur", "unifiedDataTable.grid.copyClipboardButtonTitle": "Copier la valeur de {column}", "unifiedDataTable.grid.copyColumnNameToClipBoardButton": "Copier le nom", "unifiedDataTable.grid.copyColumnValuesToClipBoardButton": "Copier la colonne", - "unifiedDataTable.grid.documentHeader": "Document", + "unifiedDataTable.grid.documentHeader": "Résumé", "unifiedDataTable.grid.editFieldButton": "Modifier le champ de la vue de données", + "unifiedDataTable.grid.esqlMultivalueFilteringDisabled": "Le filtrage multivalué n'est pas pris en charge dans ES|QL", "unifiedDataTable.grid.filterFor": "Filtrer sur", "unifiedDataTable.grid.filterForAria": "Filtrer sur cette {value}", "unifiedDataTable.grid.filterOut": "Exclure", "unifiedDataTable.grid.filterOutAria": "Exclure cette {value}", + "unifiedDataTable.grid.resetColumnWidthButton": "Réinitialiser la largeur", "unifiedDataTable.grid.selectDoc": "Sélectionner le document \"{rowNumber}\"", "unifiedDataTable.grid.viewDoc": "Afficher/Masquer les détails de la boîte de dialogue", "unifiedDataTable.gridSampleSize.fetchMoreLinkDisabledTooltip": "Pour charger plus, l'intervalle d'actualisation doit d'abord être désactivé", @@ -7560,6 +8310,8 @@ "unifiedDataTable.sampleSizeSettings.sampleSizeLabel": "Taille de l'échantillon", "unifiedDataTable.searchGenerationWithDescription": "Tableau généré par la recherche {searchTitle}", "unifiedDataTable.searchGenerationWithDescriptionGrid": "Tableau généré par la recherche {searchTitle} ({searchDescription})", + "unifiedDataTable.selectAllDocs": "Tout sélectionner ({rowsCount})", + "unifiedDataTable.selectAllRowsOnPageColumnHeader": "Sélectionner toutes les lignes visibles", "unifiedDataTable.selectColumnHeader": "Sélectionner la colonne", "unifiedDataTable.selectedResultsButtonLabel": "Sélectionné", "unifiedDataTable.selectedRowsButtonLabel": "Sélectionné", @@ -7576,9 +8328,15 @@ "unifiedDataTable.showSelectedResultsOnly": "Afficher uniquement les résultats sélectionnés", "unifiedDataTable.tableHeader.timeFieldIconTooltip": "Ce champ représente l'heure à laquelle les événements se sont produits.", "unifiedDataTable.tableHeader.timeFieldIconTooltipAriaLabel": "{timeFieldName} : ce champ représente l'heure à laquelle les événements se sont produits.", + "unifiedDocViewer.docView.logsOverview.accordion.qualityIssues.table.datasetQualityLinkTitle": "Détails de l’ensemble de données", + "unifiedDocViewer.docView.logsOverview.accordion.qualityIssues.table.field": "Problème", + "unifiedDocViewer.docView.logsOverview.accordion.qualityIssues.table.textIgnored": "champ ignoré", + "unifiedDocViewer.docView.logsOverview.accordion.qualityIssues.table.values": "Valeurs", "unifiedDocViewer.docView.logsOverview.accordion.title.cloud": "Cloud", "unifiedDocViewer.docView.logsOverview.accordion.title.other": "Autre", + "unifiedDocViewer.docView.logsOverview.accordion.title.qualityIssues": "Problèmes de qualité", "unifiedDocViewer.docView.logsOverview.accordion.title.serviceInfra": "Service et Infrastructure", + "unifiedDocViewer.docView.logsOverview.accordion.title.techPreview": "PRÉVERSION TECHNIQUE", "unifiedDocViewer.docView.logsOverview.label.cloudAvailabilityZone": "Zone de disponibilité du cloud", "unifiedDocViewer.docView.logsOverview.label.cloudInstanceId": "ID d'instance du cloud", "unifiedDocViewer.docView.logsOverview.label.cloudProjectId": "ID de projet du cloud", @@ -7601,8 +8359,9 @@ "unifiedDocViewer.docView.table.ignored.singleAboveTooltip": "La valeur dans ce champ est trop longue et ne peut pas être recherchée ni filtrée.", "unifiedDocViewer.docView.table.ignored.singleMalformedTooltip": "La valeur dans ce champ est mal formée et ne peut pas être recherchée ni filtrée.", "unifiedDocViewer.docView.table.ignored.singleUnknownTooltip": "La valeur dans ce champ a été ignorée par Elasticsearch et ne peut pas être recherchée ni filtrée.", - "unifiedDocViewer.docView.table.searchPlaceHolder": "Rechercher les noms de champs", + "unifiedDocViewer.docView.table.searchPlaceHolder": "Rechercher des noms ou valeurs de champs", "unifiedDocViewer.docViews.json.jsonTitle": "JSON", + "unifiedDocViewer.docViews.table.esqlMultivalueFilteringDisabled": "Le filtrage multivalué n'est pas pris en charge dans ES|QL", "unifiedDocViewer.docViews.table.filterForFieldPresentButtonAriaLabel": "Filtrer sur le champ", "unifiedDocViewer.docViews.table.filterForFieldPresentButtonTooltip": "Filtrer sur le champ", "unifiedDocViewer.docViews.table.filterForValueButtonAriaLabel": "Filtrer sur la valeur", @@ -7623,6 +8382,8 @@ "unifiedDocViewer.docViews.table.unindexedFieldsCanNotBeSearchedTooltip": "Les champs non indexés ou les valeurs ignorées ne peuvent pas être recherchés", "unifiedDocViewer.docViews.table.unindexedFieldsCanNotBeSearchedWarningMessage": "Il est impossible d’effectuer une recherche sur des champs non indexés", "unifiedDocViewer.docViews.table.unpinFieldLabel": "Désépingler le champ", + "unifiedDocViewer.docViews.table.viewLessButton": "Afficher moins", + "unifiedDocViewer.docViews.table.viewMoreButton": "Voir plus", "unifiedDocViewer.fieldActions.copyToClipboard": "Copier dans le presse-papiers", "unifiedDocViewer.fieldActions.filterForFieldPresent": "Filtrer sur le champ", "unifiedDocViewer.fieldActions.filterForValue": "Filtrer sur la valeur", @@ -7634,15 +8395,19 @@ "unifiedDocViewer.fieldChooser.discoverField.name": "Champ", "unifiedDocViewer.fieldChooser.discoverField.value": "Valeur", "unifiedDocViewer.fieldsTable.ariaLabel": "Valeurs des champs", + "unifiedDocViewer.fieldsTable.pinControlColumnHeader": "Épingler la colonne Champ", "unifiedDocViewer.flyout.closeButtonLabel": "Fermer", "unifiedDocViewer.flyout.documentNavigation": "Navigation dans le document", "unifiedDocViewer.flyout.docViewerDetailHeading": "Document", "unifiedDocViewer.flyout.docViewerEsqlDetailHeading": "Résultat", + "unifiedDocViewer.flyout.screenReaderDescription": "Vous êtes dans une boîte de dialogue non modale. Pour fermer la boîte de dialogue, appuyez sur Échap.", "unifiedDocViewer.flyout.toastColumnAdded": "La colonne \"{columnName}\" a été ajoutée", "unifiedDocViewer.flyout.toastColumnRemoved": "La colonne \"{columnName}\" a été supprimée", + "unifiedDocViewer.hideNullValues.switchLabel": "Masquer les champs nuls", "unifiedDocViewer.json.codeEditorAriaLabel": "Affichage JSON en lecture seule d’un document Elasticsearch", "unifiedDocViewer.json.copyToClipboardLabel": "Copier dans le presse-papiers", "unifiedDocViewer.loadingJSON": "Chargement de JSON", + "unifiedDocViewer.showOnlySelectedFields.switchLabel": "Éléments sélectionnés uniquement", "unifiedDocViewer.sourceViewer.errorMessage": "Impossible de récupérer les données pour le moment. Actualisez l'onglet et réessayez.", "unifiedDocViewer.sourceViewer.errorMessageTitle": "Une erreur s'est produite.", "unifiedDocViewer.sourceViewer.refresh": "Actualiser", @@ -7686,7 +8451,6 @@ "unifiedFieldList.fieldsAccordion.existenceTimeoutLabel": "Les informations de champ ont pris trop de temps", "unifiedFieldList.fieldStats.bucketPercentageTooltip": "{formattedPercentage} ({count, plural, one {# enregistrement} other {# enregistrements}})", "unifiedFieldList.fieldStats.calculatedFromSampleRecordsLabel": "Calculé à partir de {sampledDocumentsFormatted} {sampledDocuments, plural, one {exemple d'enregistrement} other {exemples d'enregistrement}}.", - "unifiedFieldList.fieldStats.calculatedFromSampleValuesLabel": "Calculé à partir {sampledValuesFormatted} {sampledValues, plural, one {d'un exemple de valeur} other {d’exemples de valeur}}.", "unifiedFieldList.fieldStats.calculatedFromTotalRecordsLabel": "Calculé à partir de {totalDocumentsFormatted} {totalDocuments, plural, one {enregistrement} other {enregistrements}}.", "unifiedFieldList.fieldStats.countLabel": "Décompte", "unifiedFieldList.fieldStats.displayToggleLegend": "Basculer soit", @@ -7716,7 +8480,7 @@ "unifiedFieldList.useGroupedFields.emptyFieldsLabel": "Champs vides", "unifiedFieldList.useGroupedFields.emptyFieldsLabelHelp": "Champs ne possédant aucune des valeurs spécifiées dans vos filtres.", "unifiedFieldList.useGroupedFields.metaFieldsLabel": "Champs méta", - "unifiedFieldList.useGroupedFields.noAvailableDataLabel": "Aucun champ disponible ne contient de données.", + "unifiedFieldList.useGroupedFields.noAvailableDataLabel": "Aucun champ disponible contenant des données.", "unifiedFieldList.useGroupedFields.noEmptyDataLabel": "Aucun champ vide.", "unifiedFieldList.useGroupedFields.noMetaDataLabel": "Aucun champ méta.", "unifiedFieldList.useGroupedFields.popularFieldsLabel": "Champs populaires", @@ -7777,7 +8541,7 @@ "unifiedSearch.filter.filterBar.invalidDateFormatProvidedErrorMessage": "Format de date non valide fourni", "unifiedSearch.filter.filterBar.labelWarningInfo": "Le champ {fieldName} n'existe pas dans la vue en cours.", "unifiedSearch.filter.filterBar.labelWarningText": "Avertissement", - "unifiedSearch.filter.filterBar.negatedFilterPrefix": "NON ", + "unifiedSearch.filter.filterBar.negatedFilterPrefix": "NON", "unifiedSearch.filter.filterBar.pinFilterButtonLabel": "Épingler dans toutes les applications", "unifiedSearch.filter.filterBar.pinnedFilterPrefix": "Épinglé", "unifiedSearch.filter.filterBar.preview": "Aperçu {icon}", @@ -7870,9 +8634,15 @@ "unifiedSearch.optionsList.popover.sortOrder.desc": "Décroissant", "unifiedSearch.query.queryBar.clearInputLabel": "Effacer l'entrée", "unifiedSearch.query.queryBar.comboboxAriaLabel": "Rechercher et filtrer la page {pageType}", + "unifiedSearch.query.queryBar.esqlMenu.documentation": "Documentation", + "unifiedSearch.query.queryBar.esqlMenu.exampleQueries": "Requêtes recommandées", + "unifiedSearch.query.queryBar.esqlMenu.feedback": "Soumettre un commentaire", + "unifiedSearch.query.queryBar.esqlMenu.label": "Aide sur ES|QL", + "unifiedSearch.query.queryBar.esqlMenu.quickReference": "Référence rapide", + "unifiedSearch.query.queryBar.esqlMenu.switcherLabelTitle": "Vue de données", "unifiedSearch.query.queryBar.indexPattern.addFieldButton": "Ajouter un champ à cette vue de données", "unifiedSearch.query.queryBar.indexPattern.addNewDataView": "Créer une vue de données", - "unifiedSearch.query.queryBar.indexPattern.createForMatchingIndices": "Explorer {indicesLength, plural,\n one {# index correspondant}\n other {# index correspondants}}", + "unifiedSearch.query.queryBar.indexPattern.createForMatchingIndices": "Explorer {indicesLength, plural, one {# index correspondant} other {# index correspondants}}", "unifiedSearch.query.queryBar.indexPattern.dataViewsLabel": "Vues de données", "unifiedSearch.query.queryBar.indexPattern.findDataView": "Rechercher une vue de données", "unifiedSearch.query.queryBar.indexPattern.findFilterSet": "Trouver une requête", @@ -8197,6 +8967,8 @@ "visTypeMarkdown.function.help": "Visualisation Markdown", "visTypeMarkdown.function.markdown.help": "Markdown à rendre", "visTypeMarkdown.function.openLinksInNewTab.help": "Ouvre les liens dans un nouvel onglet", + "visTypeMarkdown.markdownDescription": "Ajoutez du texte et des images à votre tableau de bord.", + "visTypeMarkdown.markdownTitleInWizard": "Texte", "visTypeMarkdown.params.fontSizeLabel": "Taille de police de base en points", "visTypeMarkdown.params.helpLinkLabel": "Aide", "visTypeMarkdown.params.openLinksLabel": "Ouvrir les liens dans un nouvel onglet", @@ -8258,7 +9030,7 @@ "visTypeTable.function.args.splitColumnHelpText": "Diviser par la configuration des dimensions de colonne", "visTypeTable.function.args.splitRowHelpText": "Diviser par la configuration des dimensions de ligne", "visTypeTable.function.args.titleHelpText": "Titre de la visualisation. Le titre est utilisé comme nom de fichier par défaut pour l'exportation CSV.", - "visTypeTable.function.args.totalFuncHelpText": "Spécifie la fonction de calcul du nombre total de lignes. Les options possibles sont : ", + "visTypeTable.function.args.totalFuncHelpText": "Spécifie la fonction de calcul du nombre total de lignes. Les options possibles sont :", "visTypeTable.function.dimension.metrics": "Indicateurs", "visTypeTable.function.dimension.splitColumn": "Diviser par colonne", "visTypeTable.function.dimension.splitRow": "Diviser par ligne", @@ -8314,8 +9086,6 @@ "visTypeTimeseries.addDeleteButtons.deleteButtonDefaultTooltip": "Supprimer", "visTypeTimeseries.addDeleteButtons.reEnableTooltip": "Réactiver", "visTypeTimeseries.addDeleteButtons.temporarilyDisableTooltip": "Désactiver temporairement", - "visTypeTimeseries.advancedSettings.allowCheckingForFailedShardsText": "Afficher un message d'avertissement pour les données partielles dans les graphiques TSVB si la requête réussit pour certaines partitions, mais échoue pour d'autres.", - "visTypeTimeseries.advancedSettings.allowCheckingForFailedShardsTitle": "Afficher les échecs de partition de requête TSVB", "visTypeTimeseries.advancedSettings.allowStringIndicesText": "Vous permet d'interroger les index Elasticsearch dans les visualisations TSVB.", "visTypeTimeseries.advancedSettings.allowStringIndicesTitle": "Autoriser les index de chaîne dans TSVB", "visTypeTimeseries.advancedSettings.maxBucketsText": "A un impact sur la densité de l'histogramme TSVB. Doit être défini sur une valeur supérieure à \"histogram:maxBars\".", @@ -8525,6 +9295,7 @@ "visTypeTimeseries.indexPatternSelect.switchModePopover.title": "Mode de vue de données", "visTypeTimeseries.indexPatternSelect.switchModePopover.useKibanaIndices": "Utiliser des vues de données Kibana", "visTypeTimeseries.indexPatternSelect.updateIndex": "Mettre à jour la visualisation avec la vue de données saisie", + "visTypeTimeseries.kbnVisTypes.metricsDescription": "Réalisez des analyses avancées de vos données temporelles.", "visTypeTimeseries.kbnVisTypes.metricsTitle": "TSVB", "visTypeTimeseries.lastValueModeIndicator.lastBucketDate": "Compartiment : {lastBucketDate}", "visTypeTimeseries.lastValueModeIndicator.lastValue": "Dernière valeur", @@ -8916,7 +9687,7 @@ "visTypeVega.vegaParser.dataExceedsSomeParamsUseTimesLimitErrorMessage": "Les données ne doivent pas avoir plus d'un paramètre {urlParam}, {valuesParam} et {sourceParam}", "visTypeVega.vegaParser.hostConfigIsDeprecatedWarningMessage": "{deprecatedConfigName} a été déclassé. Utilisez {newConfigName} à la place.", "visTypeVega.vegaParser.hostConfigValueTypeErrorMessage": "S'il est présent, le paramètre {configName} doit être un objet", - "visTypeVega.vegaParser.inputSpecDoesNotSpecifySchemaErrorMessage": "Vos spécifications requièrent un champ {schemaParam} avec une URL valide pour\nVega (voir {vegaSchemaUrl}) ou\nVega-Lite (voir {vegaLiteSchemaUrl}).\nL'URL est uniquement un identificateur. Kibana et votre navigateur n'accéderont jamais à cette URL.", + "visTypeVega.vegaParser.inputSpecDoesNotSpecifySchemaErrorMessage": "Vos spécifications requièrent un champ {schemaParam} avec une URL valide pour Vega (voir {vegaSchemaUrl}) ou Vega-Lite (voir {vegaLiteSchemaUrl}). L'URL est uniquement un identificateur. Kibana et votre navigateur n'accéderont jamais à cette URL.", "visTypeVega.vegaParser.invalidVegaSpecErrorMessage": "Spécification Vega non valide", "visTypeVega.vegaParser.kibanaConfigValueTypeErrorMessage": "S'il est présent, le paramètre {configName} doit être un objet", "visTypeVega.vegaParser.maxBoundsValueTypeWarningMessage": "{maxBoundsConfigName} doit être un tableau avec quatre nombres", @@ -9081,7 +9852,7 @@ "visualizations.confirmModal.saveDuplicateConfirmationMessage": "L'enregistrement de \"{name}\" crée un doublon de titre. Voulez-vous tout de même enregistrer ?", "visualizations.confirmModal.saveDuplicateConfirmationTitle": "Cette visualisation existe déjà", "visualizations.confirmModal.title": "Modifications non enregistrées", - "visualizations.controls.notificationMessage": "Les contrôles d'entrée sont déclassés et seront supprimés dans une prochaine version. Utilisez les nouveaux contrôles pour filtrer les données de votre tableau de bord et interagir avec elles. ", + "visualizations.controls.notificationMessage": "Les contrôles d'entrée sont déclassés et seront supprimés dans une prochaine version. Utilisez les nouveaux contrôles pour filtrer les données de votre tableau de bord et interagir avec elles.", "visualizations.createVisualization.failedToLoadErrorMessage": "Impossible de charger la visualisation", "visualizations.createVisualization.noIndexPatternOrSavedSearchIdErrorMessage": "Vous devez fournir un indexPattern ou un savedSearchId", "visualizations.createVisualization.noVisTypeErrorMessage": "Vous devez fournir un type de visualisation valide", @@ -9090,6 +9861,7 @@ "visualizations.editor.createBreadcrumb": "Créer", "visualizations.editor.defaultEditBreadcrumbText": "Modifier la visualisation", "visualizations.editVisualization.readOnlyErrorMessage": "Les visualisations {visTypeTitle} sont en lecture seule et ne peuvent pas être ouvertes dans l'éditeur", + "visualizations.embeddable.errorTitle": "Impossible de charger la visualisation", "visualizations.embeddable.inspectorTitle": "Inspecteur", "visualizations.embeddable.legacyURLConflict.errorMessage": "Cette visualisation a la même URL qu'un alias hérité. Désactiver l'alias pour résoudre cette erreur : {json}", "visualizations.embeddable.placeholderTitle": "Titre de l'espace réservé", @@ -9137,6 +9909,8 @@ "visualizations.newChart.libraryMode.new": "nouveau", "visualizations.newChart.libraryMode.old": "âge", "visualizations.newGaugeChart.notificationMessage": "La nouvelle bibliothèque de graphiques de jauge ne prend pas encore en charge l'agrégation de graphiques fractionnés. {conditionalMessage}", + "visualizations.newVisWizard.aggBasedGroupDescription": "Utilisez notre bibliothèque Visualize classique pour créer des graphiques basés sur des agrégations.", + "visualizations.newVisWizard.aggBasedGroupTitle": "Basé sur une agrégation", "visualizations.newVisWizard.chooseSourceTitle": "Choisir une source", "visualizations.newVisWizard.filterVisTypeAriaLabel": "Filtrer un type de visualisation", "visualizations.newVisWizard.goBackLink": "Sélectionner une visualisation différente", @@ -9147,6 +9921,7 @@ "visualizations.newVisWizard.searchSelection.notFoundLabel": "Aucun recherche enregistrée ni aucun index correspondants n'ont été trouvés.", "visualizations.newVisWizard.searchSelection.savedObjectType.dataView": "Vue de données", "visualizations.newVisWizard.searchSelection.savedObjectType.search": "Recherche enregistrée", + "visualizations.newVisWizard.title": "Nouvelle visualisation", "visualizations.noDataView.label": "vue de données", "visualizations.noMatchRoute.bannerText": "L'application Visualize ne reconnaît pas cet itinéraire : {route}.", "visualizations.noMatchRoute.bannerTitleText": "Page introuvable", @@ -9194,6 +9969,7 @@ "visualizations.visualizeListingDashboardAppName": "Application Tableau de bord", "visualizations.visualizeListingDeleteErrorTitle": "Erreur lors de la suppression de la visualisation", "visualizations.visualizeListingDeleteErrorTitle.duplicateWarning": "L'enregistrement de \"{value}\" crée un doublon de titre.", + "visualizations.visualizeSavedObjectName": "Visualisation", "visualizationUiComponents.colorPicker.seriesColor.label": "Couleur de la série", "visualizationUiComponents.colorPicker.tooltip.auto": "Lens choisit automatiquement des couleurs à votre place sauf si vous spécifiez une couleur personnalisée.", "visualizationUiComponents.colorPicker.tooltip.custom": "Effacez la couleur personnalisée pour revenir au mode \"Auto\".", @@ -9252,8 +10028,9 @@ "xpack.actions.availableConnectorFeatures.compatibility.alertingRules": "Règles d'alerting", "xpack.actions.availableConnectorFeatures.compatibility.cases": "Cas", "xpack.actions.availableConnectorFeatures.compatibility.generativeAIForObservability": "IA générative pour l'observabilité", - "xpack.actions.availableConnectorFeatures.compatibility.generativeAIForSearchPlayground": "L'IA générative pour Search Playground", + "xpack.actions.availableConnectorFeatures.compatibility.generativeAIForSearchPlayground": "IA générative pour Search", "xpack.actions.availableConnectorFeatures.compatibility.generativeAIForSecurity": "IA générative pour la sécurité", + "xpack.actions.availableConnectorFeatures.compatibility.securitySolution": "Solution de sécurité", "xpack.actions.availableConnectorFeatures.securitySolution": "Solution de sécurité", "xpack.actions.availableConnectorFeatures.uptime": "Uptime", "xpack.actions.builtin.cases.jiraTitle": "Jira", @@ -9273,9 +10050,10 @@ "xpack.actions.serverSideErrors.unavailableLicenseInformationErrorMessage": "Les actions sont indisponibles - les informations de licence ne sont pas disponibles actuellement.", "xpack.actions.subActionsFramework.urlValidationError": "Erreur lors de la validation de l'URL : {message}", "xpack.actions.urlAllowedHostsConfigurationError": "Le {field} cible \"{value}\" n'est pas ajouté à la configuration Kibana xpack.actions.allowedHosts", + "xpack.aiAssistant.aiAssistantLabel": "Assistant d'intelligence artificielle", "xpack.aiAssistant.askAssistantButton.buttonLabel": "Demander à l'assistant", "xpack.aiAssistant.askAssistantButton.popoverContent": "Obtenez des informations relatives à vos données grâce à l'assistant d'Elastic", - "xpack.aiAssistant.assistantSetup.title": "Bienvenue sur l'assistant d'intelligence artificielle d'Elastic", + "xpack.aiAssistant.assistantSetup.title": "Bienvenue sur Elastic AI Assistant", "xpack.aiAssistant.chatActionsMenu.euiButtonIcon.menuLabel": "Menu", "xpack.aiAssistant.chatActionsMenu.euiToolTip.moreActionsLabel": "Plus d'actions", "xpack.aiAssistant.chatCollapsedItems.hideEvents": "Masquer {count} événements", @@ -9283,6 +10061,7 @@ "xpack.aiAssistant.chatCollapsedItems.toggleButtonLabel": "Afficher/masquer les éléments", "xpack.aiAssistant.chatFlyout.euiButtonIcon.expandConversationListLabel": "Développer la liste des conversations", "xpack.aiAssistant.chatFlyout.euiButtonIcon.newChatLabel": "Nouveau chat", + "xpack.aiAssistant.chatFlyout.euiFlyoutResizable.aiAssistantLabel": "Menu volant Chat de l'assistant d'IA", "xpack.aiAssistant.chatFlyout.euiToolTip.collapseConversationListLabel": "Réduire la liste des conversations", "xpack.aiAssistant.chatFlyout.euiToolTip.expandConversationListLabel": "Développer la liste des conversations", "xpack.aiAssistant.chatFlyout.euiToolTip.newChatLabel": "Nouveau chat", @@ -9307,6 +10086,10 @@ "xpack.aiAssistant.chatTimeline.messages.system.label": "Système", "xpack.aiAssistant.chatTimeline.messages.user.label": "Vous", "xpack.aiAssistant.checkingKbAvailability": "Vérification de la disponibilité de la base de connaissances", + "xpack.aiAssistant.conversationList.deleteConversationIconLabel": "Supprimer", + "xpack.aiAssistant.conversationList.errorMessage": "Échec de chargement", + "xpack.aiAssistant.conversationList.noConversations": "Aucune conversation", + "xpack.aiAssistant.conversationList.title": "Précédemment", "xpack.aiAssistant.conversationStartTitle": "a démarré une conversation", "xpack.aiAssistant.couldNotFindConversationContent": "Impossible de trouver une conversation avec l'ID {conversationId}. Assurez-vous que la conversation existe et que vous y avez accès.", "xpack.aiAssistant.couldNotFindConversationTitle": "Conversation introuvable", @@ -9346,7 +10129,7 @@ "xpack.aiAssistant.technicalPreviewBadgeDescription": "GTP4 est nécessaire pour bénéficier d'une meilleure expérience avec les appels de fonctions (par exemple lors de la réalisation d'analyse de la cause d'un problème, de la visualisation de données et autres). GPT3.5 peut fonctionner pour certains des workflows les plus simples comme les explications d'erreurs ou pour bénéficier d'une expérience comparable à ChatGPT au sein de Kibana à partir du moment où les appels de fonctions ne sont pas fréquents.", "xpack.aiAssistant.userExecutedFunctionEvent": "a exécuté la fonction {functionName}", "xpack.aiAssistant.userSuggestedFunctionEvent": "a demandé la fonction {functionName}", - "xpack.aiAssistant.welcomeMessage.div.checkTrainedModelsToLabel": " {retryInstallingLink} ou vérifiez {trainedModelsLink} pour vous assurer que {modelName} est déployé et en cours d'exécution.", + "xpack.aiAssistant.welcomeMessage.div.checkTrainedModelsToLabel": "{retryInstallingLink} ou vérifiez {trainedModelsLink} pour vous assurer que {modelName} est déployé et en cours d'exécution.", "xpack.aiAssistant.welcomeMessage.div.settingUpKnowledgeBaseLabel": "Configuration de la base de connaissances", "xpack.aiAssistant.welcomeMessage.inspectErrorsButtonEmptyLabel": "Inspecter les problèmes", "xpack.aiAssistant.welcomeMessage.issuesDescriptionListTitleLabel": "Problèmes", @@ -9362,9 +10145,19 @@ "xpack.aiAssistant.welcomeMessageKnowledgeBase.yourKnowledgeBaseIsNotSetUpCorrectlyLabel": "Votre base de connaissances n'a pas été configurée.", "xpack.aiAssistant.welcomeMessageKnowledgeBaseSetupErrorPanel.retryInstallingLinkLabel": "Réessayer l'installation", "xpack.aiops.actions.openChangePointInMlAppName": "Ouvrir dans AIOps Labs", + "xpack.aiops.analysis.analysisTypeDipFallbackInfoTitle": "Meilleurs éléments pour la plage temporelle de référence de base", + "xpack.aiops.analysis.analysisTypeDipInfoContent": "Le taux de log médian pour la plage temporelle d'écart-type sélectionnée est inférieur à la référence de base. Le tableau des résultats de l'analyse présente donc des éléments statistiquement significatifs inclus dans la plage temporelle de base qui sont moins nombreux ou manquant dans la plage temporelle d'écart-type. La colonne \"doc count\" (décompte de documents) renvoie à la quantité de documents dans la plage temporelle de base.", + "xpack.aiops.analysis.analysisTypeDipInfoContentFallback": "La plage temporelle de déviation ne contient aucun document. Les résultats montrent donc les catégories de message des meilleurs logs et les valeurs des champs pour la période de référence.", + "xpack.aiops.analysis.analysisTypeDipInfoTitle": "Baisse du taux de log", + "xpack.aiops.analysis.analysisTypeInfoTitlePrefix": "Type d'analyse :", + "xpack.aiops.analysis.analysisTypeSpikeFallbackInfoTitle": "Meilleurs éléments pour la plage temporelle de déviation", + "xpack.aiops.analysis.analysisTypeSpikeInfoContent": "Le taux de log médian pour la plage temporelle d'écart-type sélectionnée est inférieur à la référence de base. Le tableau des résultats de l'analyse présente donc des éléments statistiquement significatifs inclus dans la plage temporelle d'écart-type, qui contribuent au pic. La colonne \"doc count\" (décompte de documents) renvoie à la quantité de documents dans la plage temporelle d'écart-type.", + "xpack.aiops.analysis.analysisTypeSpikeInfoContentFallback": "La plage temporelle de référence de base ne contient aucun document. Les résultats montrent donc les catégories de message des meilleurs logs et les valeurs des champs pour la plage temporelle de déviation.", + "xpack.aiops.analysis.analysisTypeSpikeInfoTitle": "Pic du taux de log", "xpack.aiops.analysis.columnSelectorAriaLabel": "Filtrer les colonnes", "xpack.aiops.analysis.columnSelectorNotEnoughColumnsSelected": "Au moins une colonne doit être sélectionnée.", "xpack.aiops.analysis.errorCallOutTitle": "Génération {errorCount, plural, one {de l'erreur suivante} other {des erreurs suivantes}} au cours de l'analyse.", + "xpack.aiops.analysis.fieldsButtonLabel": "Champs", "xpack.aiops.analysis.fieldSelectorNotEnoughFieldsSelected": "Le regroupement nécessite la sélection d'au moins 2 champs.", "xpack.aiops.analysis.fieldSelectorPlaceholder": "Recherche", "xpack.aiops.analysisCompleteLabel": "Analyse terminée", @@ -9378,7 +10171,7 @@ "xpack.aiops.changePointDetection.actions.filterOutValueAction": "Exclure la valeur", "xpack.aiops.changePointDetection.actionsColumn": "Actions", "xpack.aiops.changePointDetection.addButtonLabel": "Ajouter", - "xpack.aiops.changePointDetection.aggregationIntervalTitle": "Intervalle d'agrégation : ", + "xpack.aiops.changePointDetection.aggregationIntervalTitle": "Intervalle d'agrégation :", "xpack.aiops.changePointDetection.applyTimeRangeLabel": "Appliquer la plage temporelle", "xpack.aiops.changePointDetection.attachChartsLabel": "Attacher les graphiques", "xpack.aiops.changePointDetection.attachmentTitle": "Point de modification : {function}({metric}){splitBy}", @@ -9424,7 +10217,7 @@ "xpack.aiops.changePointDetection.selectMetricFieldLabel": "Champ d'indicateur", "xpack.aiops.changePointDetection.selectSpitFieldLabel": "Diviser le champ", "xpack.aiops.changePointDetection.spikeDescription": "Un pic significatif existe au niveau de ce point.", - "xpack.aiops.changePointDetection.splitByTitle": " diviser par \"{splitField}\"", + "xpack.aiops.changePointDetection.splitByTitle": "diviser par \"{splitField}\"", "xpack.aiops.changePointDetection.stepChangeDescription": "La modification indique une hausse ou une baisse statistiquement significative dans la distribution des valeurs.", "xpack.aiops.changePointDetection.submitDashboardAttachButtonLabel": "Attacher", "xpack.aiops.changePointDetection.timeColumn": "Heure", @@ -9455,6 +10248,15 @@ "xpack.aiops.embeddableChangePointChart.viewTypeSelector.chartsLabel": "Graphiques", "xpack.aiops.embeddableChangePointChart.viewTypeSelector.tableLabel": "Tableau", "xpack.aiops.embeddableChangePointChartDisplayName": "Modifier la détection du point", + "xpack.aiops.embeddablePatternAnalysis.attachmentTitle": "Analyse du modèle : {fieldName}", + "xpack.aiops.embeddablePatternAnalysis.config.applyAndCloseLabel": "Appliquer et fermer", + "xpack.aiops.embeddablePatternAnalysis.config.applyFlyoutAriaLabel": "Appliquer les modifications", + "xpack.aiops.embeddablePatternAnalysis.config.cancelButtonLabel": "Annuler", + "xpack.aiops.embeddablePatternAnalysis.config.dataViewLabel": "Vue de données", + "xpack.aiops.embeddablePatternAnalysis.config.dataViewSelectorPlaceholder": "Sélectionner la vue de données", + "xpack.aiops.embeddablePatternAnalysis.config.title.edit": "Modifier l'analyse des modèles", + "xpack.aiops.embeddablePatternAnalysis.config.title.new": "Créer une analyse de modèle", + "xpack.aiops.embeddablePatternAnalysisDisplayName": "Analyse du modèle", "xpack.aiops.fieldContextPopover.descriptionTooltipContent": "Afficher les principales valeurs de champ", "xpack.aiops.fieldContextPopover.descriptionTooltipLogPattern": "La valeur du champ pour ce champ montre un exemple du modèle de champ de texte important identifié.", "xpack.aiops.fieldContextPopover.notTopTenValueMessage": "Le terme sélectionné n'est pas dans le top 10", @@ -9477,11 +10279,15 @@ "xpack.aiops.logCategorization.counts": "{count} {count, plural, one {Modèle trouvé} other {Modèles trouvés}}", "xpack.aiops.logCategorization.embeddableMenu.aria": "Options d'analyse de modèles", "xpack.aiops.logCategorization.embeddableMenu.minimumTimeRange.tooltip": "Ajoute une plage temporelle plus large à l’analyse afin d’améliorer la précision du modèle.", + "xpack.aiops.logCategorization.embeddableMenu.minimumTimeRangeOptionsRowAriaLabel": "Sélectionnez une plage temporelle minimale", "xpack.aiops.logCategorization.embeddableMenu.minimumTimeRangeOptionsRowLabel": "Plage temporelle minimale", - "xpack.aiops.logCategorization.embeddableMenu.patternAnalysisSettingsTitle": " Paramètres d’analyse du modèle", + "xpack.aiops.logCategorization.embeddableMenu.patternAnalysisSettingsTitle": "Paramètres d’analyse du modèle", "xpack.aiops.logCategorization.embeddableMenu.selectedFieldRowLabel": "Champ sélectionné", + "xpack.aiops.logCategorization.embeddableMenu.textFieldWarning.title": "La vue de données sélectionnée ne contient aucun champ de texte.", + "xpack.aiops.logCategorization.embeddableMenu.textFieldWarning.title.description": "L'analyse de modèle ne peut être exécutée que sur des vues de données comportant un champ de texte.", "xpack.aiops.logCategorization.embeddableMenu.tooltip": "Options", "xpack.aiops.logCategorization.embeddableMenu.totalPatternsMessage": "Modèles totaux dans {minimumTimeRangeOption} : {categoryCount}", + "xpack.aiops.logCategorization.embeddableMenu.totalPatternsMessage2": "Aucun temps supplémentaire ne sera ajouté à la plage que vous avez spécifiée avec le sélecteur de temps.", "xpack.aiops.logCategorization.emptyPromptBody": "L'analyse de modèle de log regroupe les messages dans des modèles courants.", "xpack.aiops.logCategorization.emptyPromptTitle": "Sélectionner un champ de texte et cliquer sur exécuter l'analyse du modèle pour lancer l'analyse", "xpack.aiops.logCategorization.errorLoadingCategories": "Erreur lors du chargement des catégories", @@ -9494,6 +10300,11 @@ "xpack.aiops.logCategorization.filterOut": "Exclure {values, plural, one {modèle} other {modèles}} dans Discover", "xpack.aiops.logCategorization.flyout.filterIn": "Filtrer sur {values, plural, one {modèle} other {modèles}}", "xpack.aiops.logCategorization.flyout.filterOut": "Exclure {values, plural, one {modèle} other {modèles}}", + "xpack.aiops.logCategorization.minimumTimeRange.1month": "1 mois", + "xpack.aiops.logCategorization.minimumTimeRange.1week": "1 semaine", + "xpack.aiops.logCategorization.minimumTimeRange.3months": "3 mois", + "xpack.aiops.logCategorization.minimumTimeRange.6months": "6 mois", + "xpack.aiops.logCategorization.minimumTimeRange.noMin": "Utiliser la plage spécifiée dans le sélecteur de temps", "xpack.aiops.logCategorization.noCategoriesBody": "Assurez-vous que le champ sélectionné est rempli dans la plage temporelle sélectionnée.", "xpack.aiops.logCategorization.noCategoriesTitle": "Aucun modèle n'a été trouvé", "xpack.aiops.logCategorization.noDocsBody": "Assurez-vous que la plage temporelle sélectionnée contient des documents.", @@ -9515,13 +10326,16 @@ "xpack.aiops.logCategorization.randomSamplerSettingsPopUp.randomSamplerPercentageRowLabel": "Pourcentage d'échantillonnage", "xpack.aiops.logCategorization.randomSamplerSettingsPopUp.randomSamplerRowLabel": "Échantillonnage aléatoire", "xpack.aiops.logCategorization.runButton": "Exécuter l'analyse du modèle", - "xpack.aiops.logCategorization.selectedCounts": " | {count} sélectionné(s)", + "xpack.aiops.logCategorization.selectedCounts": "| {count} sélectionné(s)", "xpack.aiops.logCategorization.selectedResultsButtonLabel": "Sélectionné", "xpack.aiops.logCategorization.tabs.bucket": "Compartiment", "xpack.aiops.logCategorization.tabs.bucket.tooltip": "Modèles apparaissant dans le compartiment anormal.", "xpack.aiops.logCategorization.tabs.fullTimeRange": "Plage temporelle entière", "xpack.aiops.logCategorization.tabs.fullTimeRange.tooltip": "Modèles apparaissant dans la plage temporelle choisie pour la page.", "xpack.aiops.logCategorizationTimeSeriesWarning.description": "L'analyse du modèle de log ne fonctionne que sur des index temporels.", + "xpack.aiops.logRateAnalysis.fieldCandidates.ecsIdentifiedMessage": "Les documents sources ont été identifiés comme étant conformes à ECS.", + "xpack.aiops.logRateAnalysis.fieldCandidates.fieldsDropdownHintMessage": "Utilisez le menu déroulant \"Champs\" pour modifier la sélection.", + "xpack.aiops.logRateAnalysis.fieldCandidates.fieldsSelectedMessage": "{selectedItemsCount} champs sur {allItemsCount} ont été présélectionnés pour l'analyse.", "xpack.aiops.logRateAnalysis.loadingState.doneMessage": "Terminé.", "xpack.aiops.logRateAnalysis.loadingState.groupingResults": "Transformation de paires champ/valeur significatives en groupes.", "xpack.aiops.logRateAnalysis.loadingState.identifiedFieldCandidates": "{fieldCandidatesCount, plural, one {# candidat de champ identifié} other {# candidats de champs identifiés}}.", @@ -9539,7 +10353,7 @@ "xpack.aiops.logRateAnalysis.page.emptyPromptBody": "La fonction d'analyse des pics de taux de log identifie les combinaisons champ/valeur statistiquement significatives qui contribuent à un pic ou une baisse de taux de log.", "xpack.aiops.logRateAnalysis.page.emptyPromptTitle": "Commencez par cliquer sur un pic ou une baisse dans l'histogramme.", "xpack.aiops.logRateAnalysis.page.fieldFilterApplyButtonLabel": "Appliquer", - "xpack.aiops.logRateAnalysis.page.fieldFilterHelpText": "Désélectionnez les champs non pertinents pour les supprimer des groupes et cliquez sur le bouton Appliquer pour réexécuter le regroupement. Utilisez la barre de recherche pour filtrer la liste, puis sélectionnez/désélectionnez plusieurs champs avec les actions ci-dessous.", + "xpack.aiops.logRateAnalysis.page.fieldFilterHelpText": "Désélectionnez les champs non pertinents pour les supprimer de l'analyse et cliquez sur le bouton Appliquer pour réexécuter l'analyse. Utilisez la barre de recherche pour filtrer la liste, puis sélectionnez/désélectionnez plusieurs champs avec les actions ci-dessous.", "xpack.aiops.logRateAnalysis.page.fieldSelector.deselectAllItems": "Tout désélectionner", "xpack.aiops.logRateAnalysis.page.fieldSelector.deselectAllSearchedItems": "Désélectionner les éléments filtrés", "xpack.aiops.logRateAnalysis.page.fieldSelector.selectAllItems": "Tout sélectionner", @@ -9600,11 +10414,15 @@ "xpack.aiops.logRateAnalysis.resultsTableGroups.impactLabelColumnTooltip": "Niveau d'impact du groupe sur la différence de taux de messages", "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateChangeLabelColumnTooltip": "Le facteur par lequel le taux de journalisation a changé. Cette valeur est normalisée afin de tenir compte des différentes longueurs des plages temporelles de référence et d’écart.", "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateColumnTooltip": "Représentation visuelle de l'impact du groupe sur la différence de taux de messages.", - "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateDocDecreaseLabel": "les documents descendent jusqu'à 0 de {baselineBucketRate} au niveau de référence", - "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateDocIncreaseLabel": "{deviationBucketRate} {deviationBucketRate, plural, one {doc} other {docs}} remontent de 0 au niveau de référence", + "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateDocDecreaseLabel": "jusqu'à 0 depuis {baselineBucketRate} au niveau de référence", + "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateDocIncreaseLabel": "jusqu'à {deviationBucketRate} depuis 0 au niveau de référence", + "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateFactorDecreaseLabel": "{roundedFactor} fois inférieur", + "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateFactorIncreaseLabel": "{roundedFactor} fois supérieur", "xpack.aiops.logRateAnalysisTimeSeriesWarning.description": "L'analyse des taux de log ne fonctionne que sur des index temporels.", "xpack.aiops.miniHistogram.noDataLabel": "S. O.", + "xpack.aiops.navMenu.mlAppNameText": "Machine Learning et Analytique", "xpack.aiops.observabilityAIAssistantContextualInsight.logRateAnalysisTitle": "Causes possibles et résolutions", + "xpack.aiops.patternAnalysis.typeDisplayName": "analyse du modèle", "xpack.aiops.progressAriaLabel": "Progression", "xpack.aiops.progressTitle": "Progression : {progress} % — {progressMessage}", "xpack.aiops.rerunAnalysisButtonTitle": "Lancer l'analyse", @@ -9783,7 +10601,7 @@ "xpack.alerting.rulesClient.validateActions.actionsWithInvalidThrottles": "La fréquence de l'action ne peut pas être inférieure à l'intervalle de planification de {scheduleIntervalText} : {groups}", "xpack.alerting.rulesClient.validateActions.actionsWithInvalidTimeRange": "La plage temporelle du filtre d'alertes de l'action a une valeur non valide : {hours}", "xpack.alerting.rulesClient.validateActions.actionWithInvalidTimeframe": "La durée du filtre d'alertes de l'action a des champs manquants : jours, heures ou fuseau horaire : {uuids}", - "xpack.alerting.rulesClient.validateActions.errorSummary": "Impossible de valider les actions en raison {errorNum, plural, one {de l'erreur suivante :} other {des # erreurs suivantes :\n-}} {errorList}", + "xpack.alerting.rulesClient.validateActions.errorSummary": "Impossible de valider les actions en raison {errorNum, plural, one {de l'erreur suivante :} other {des # erreurs suivantes : -}} {errorList}", "xpack.alerting.rulesClient.validateActions.hasDuplicatedUuid": "Les actions ont des UUID en double", "xpack.alerting.rulesClient.validateActions.invalidGroups": "Groupes d'actions non valides : {groups}", "xpack.alerting.rulesClient.validateActions.misconfiguredConnector": "Connecteurs non valides : {groups}", @@ -9810,27 +10628,29 @@ "xpack.alerting.taskRunner.warning.maxQueuedActions": "Le nombre maximal d'actions en file d'attente a été atteint ; les actions excédentaires n'ont pas été déclenchées.", "xpack.apm..breadcrumb.apmLabel": "APM", "xpack.apm.a.thresholdMet": "Seuil atteint", + "xpack.apm.add.apm.agent.button.": "Ajouter un APM", "xpack.apm.addDataButtonLabel": "Ajouter des données", + "xpack.apm.addDataContextMenu.link": "Ajouter des données", "xpack.apm.agent_explorer.error.missing_configuration": "Pour utiliser la toute dernière version de l’agent, vous devez définir xpack.apm.latestAgentVersionsUrl.", "xpack.apm.agentConfig.allOptionLabel": "Tous", - "xpack.apm.agentConfig.apiRequestSize.description": "Taille totale compressée maximale du corps de la requête envoyé à l'API d'ingestion du serveur APM depuis un encodage fragmenté (diffusion HTTP).\nVeuillez noter qu'un léger dépassement est possible.\n\nLes unités d'octets autorisées sont `b`, `kb` et `mb`. `1kb` correspond à `1024b`.", + "xpack.apm.agentConfig.apiRequestSize.description": "Taille totale compressée maximale du corps de la requête envoyé à l'API d'ingestion du serveur APM depuis un encodage fragmenté (diffusion HTTP). Veuillez noter qu'un léger dépassement est possible. Les unités d'octets autorisées sont `b`, `kb` et `mb`. `1kb` correspond à `1024b`.", "xpack.apm.agentConfig.apiRequestSize.label": "Taille de la requête API", - "xpack.apm.agentConfig.apiRequestTime.description": "Durée maximale de l'ouverture d'une requête HTTP sur le serveur APM.\n\nREMARQUE : cette valeur doit être inférieure à celle du paramètre `read_timeout` du serveur APM.", + "xpack.apm.agentConfig.apiRequestTime.description": "Durée maximale de l'ouverture d'une requête HTTP sur le serveur APM. REMARQUE : cette valeur doit être inférieure à celle du paramètre `read_timeout` du serveur APM.", "xpack.apm.agentConfig.apiRequestTime.label": "Heure de la requête API", - "xpack.apm.agentConfig.applicationPackages.description": "Permet de déterminer si un cadre de trace de pile est un cadre dans l'application ou un cadre de bibliothèque. Cela permet à l'application APM de réduire les cadres de pile du code de la bibliothèque et de mettre en surbrillance les cadres de pile qui proviennent de votre application. Plusieurs packages racine peuvent être définis sous forme de liste séparée par des virgules ; il n'est pas nécessaire de configurer des sous-packages. Étant donné que ce paramètre aide à déterminer les classes à analyser au démarrage, la définition de cette option peut également améliorer le temps de démarrage.\n\nVous devez définir cette option afin d'utiliser les annotations d'API `@CaptureTransaction` et `@CaptureSpan`.", + "xpack.apm.agentConfig.applicationPackages.description": "Permet de déterminer si un cadre de trace de pile est un cadre dans l'application ou un cadre de bibliothèque. Cela permet à l'application APM de réduire les cadres de pile du code de la bibliothèque et de mettre en surbrillance les cadres de pile qui proviennent de votre application. Plusieurs packages racine peuvent être définis sous forme de liste séparée par des virgules ; il n'est pas nécessaire de configurer des sous-packages. Étant donné que ce paramètre aide à déterminer les classes à analyser au démarrage, la définition de cette option peut également améliorer le temps de démarrage. Vous devez définir cette option afin d'utiliser les annotations d'API `@CaptureTransaction` et `@CaptureSpan`.", "xpack.apm.agentConfig.applicationPackages.label": "Packages de l'application", - "xpack.apm.agentConfig.captureBody.description": "Pour les transactions qui sont des requêtes HTTP, l'agent peut éventuellement capturer le corps de la requête (par ex., variables POST).\nPour les transactions qui sont initiées par la réception d'un message depuis un agent de message, l'agent peut capturer le corps du message texte.", + "xpack.apm.agentConfig.captureBody.description": "Pour les transactions qui sont des requêtes HTTP, l'agent peut éventuellement capturer le corps de la requête (par ex., variables POST). Pour les transactions qui sont initiées par la réception d'un message depuis un agent de message, l'agent peut capturer le corps du message texte.", "xpack.apm.agentConfig.captureBody.label": "Capturer le corps", - "xpack.apm.agentConfig.captureBodyContentTypes.description": "Configure les types de contenu qui doivent être enregistrés.\n\nLes valeurs par défaut se terminent par un caractère générique afin que les types de contenu tels que `text/plain; charset=utf-8` soient également capturés.", + "xpack.apm.agentConfig.captureBodyContentTypes.description": "Configure les types de contenu qui doivent être enregistrés. Les valeurs par défaut se terminent par un caractère générique afin que les types de contenu tels que `text/plain; charset=utf-8` soient également capturés.", "xpack.apm.agentConfig.captureBodyContentTypes.label": "Capturer les types de contenu du corps", - "xpack.apm.agentConfig.captureHeaders.description": "Si cette option est définie sur `true`, l'agent capturera les en-têtes de la requête HTTP et de la réponse (y compris les cookies), ainsi que les en-têtes/les propriétés du message lors de l'utilisation de frameworks de messagerie (tels que Kafka).\n\nREMARQUE : Si `false` est défini, cela permet de réduire la bande passante du réseau, l'espace disque et les allocations d'objets.", + "xpack.apm.agentConfig.captureHeaders.description": "Si cette option est définie sur `true`, l'agent capturera les en-têtes de la requête HTTP et de la réponse (y compris les cookies), ainsi que les en-têtes/les propriétés du message lors de l'utilisation de frameworks de messagerie (tels que Kafka). REMARQUE : Si `false` est défini, cela permet de réduire la bande passante du réseau, l'espace disque et les allocations d'objets.", "xpack.apm.agentConfig.captureHeaders.label": "Capturer les en-têtes", - "xpack.apm.agentConfig.captureJmxMetrics.description": "Enregistrer les indicateurs de JMX sur le serveur APM\n\nPeut contenir plusieurs définitions d'indicateurs JMX séparées par des virgules :\n\n`object_name[] attribute[:metric_name=]`\n\nPour en savoir plus, consultez la documentation de l'agent Java.", + "xpack.apm.agentConfig.captureJmxMetrics.description": "Les indicateurs du rapport de JMX vers le serveur APM peuvent contenir plusieurs définitions d’indicateurs JMX séparés par des virgules : `object_name[] attribute[:metric_name=]` Consultez la documentation de l'agent Java pour plus de détails.", "xpack.apm.agentConfig.captureJmxMetrics.label": "Capturer les indicateurs JMX", "xpack.apm.agentConfig.chooseService.editButton": "Modifier", "xpack.apm.agentConfig.chooseService.service.environment.label": "Environnement", "xpack.apm.agentConfig.chooseService.service.name.label": "Nom de service", - "xpack.apm.agentConfig.circuitBreakerEnabled.description": "Nombre booléen spécifiant si le disjoncteur doit être activé ou non. Lorsqu'il est activé, l'agent interroge régulièrement les monitorings de tension pour détecter l'état de tension du système/du processus/de la JVM. Si L'UN des monitorings détecte un signe de tension, l'agent s'interrompt, comme si l'option de configuration `recording` était définie sur `false`, réduisant ainsi la consommation des ressources au minimum. Pendant l'interruption, l'agent continue à interroger les mêmes monitorings pour vérifier si l'état de tension a été allégé. Si TOUS les monitorings indiquent que le système, le processus et la JVM ne sont plus en état de tension, l'agent reprend son activité et redevient entièrement fonctionnel.", + "xpack.apm.agentConfig.circuitBreakerEnabled.description": "Nombre booléen spécifiant si le disjoncteur doit être activé ou non. Lorsqu'il est activé, l'agent interroge régulièrement les monitorings de tension pour détecter l'état de tension du système/du processus/de la JVM. Si L'UN des monitorings détecte un signe de tension, l'agent s'interrompt, comme si l'option de configuration `recording` était définie sur `false`, réduisant ainsi la consommation des ressources au minimum. Pendant l'interruption, l'agent continue à interroger les mêmes monitorings pour vérifier si l'état de tension a été allégé. Si TOUS les monitorings indiquent que le système, le processus et la JVM ne sont plus en état de tension, l'agent reprend son activité et redevient entièrement fonctionnel.", "xpack.apm.agentConfig.circuitBreakerEnabled.label": "Disjoncteur activé", "xpack.apm.agentConfig.configTable.appliedTooltipMessage": "Appliqué par au moins un agent", "xpack.apm.agentConfig.configTable.configTable.failurePromptText": "La liste des configurations d'agent n'a pas pu être récupérée. Votre utilisateur ne dispose peut-être pas d'autorisations suffisantes.", @@ -9846,7 +10666,7 @@ "xpack.apm.agentConfig.context_propagation_only.label": "Propagation du contexte seulement", "xpack.apm.agentConfig.createConfigButtonLabel": "Créer une configuration", "xpack.apm.agentConfig.createConfigTitle": "Créer une configuration", - "xpack.apm.agentConfig.dedotCustomMetrics.description": "Remplace les points par des traits de soulignement dans les noms des indicateurs personnalisés.\n\nAVERTISSEMENT : L'attribution de la valeur `false` peut entraîner des conflits de mapping car les points indiquent une imbrication dans Elasticsearch.\nUn tel conflit peut se produire par exemple entre deux indicateurs si l'un se nomme `foo` et l'autre `foo.bar`.\nLe premier mappe `foo` sur un nombre, et le second indicateur mappe `foo` en tant qu'objet.", + "xpack.apm.agentConfig.dedotCustomMetrics.description": "Remplace les points par des traits de soulignement dans les noms des indicateurs personnalisés. AVERTISSEMENT : L'attribution de la valeur `false` peut entraîner des conflits de mapping car les points indiquent une imbrication dans Elasticsearch. Un tel conflit peut se produire par exemple entre deux indicateurs si l'un se nomme `foo` et l'autre `foo.bar`. Le premier mappe `foo` sur un nombre, et le second indicateur mappe `foo` en tant qu'objet.", "xpack.apm.agentConfig.dedotCustomMetrics.label": "Retirer les points des indicateurs personnalisés", "xpack.apm.agentConfig.deleteModal.cancel": "Annuler", "xpack.apm.agentConfig.deleteModal.confirm": "Supprimer", @@ -9856,30 +10676,30 @@ "xpack.apm.agentConfig.deleteSection.deleteConfigFailedTitle": "La configuration n'a pas pu être supprimée", "xpack.apm.agentConfig.deleteSection.deleteConfigSucceededText": "Vous avez supprimé une configuration de \"{serviceName}\". La propagation jusqu'aux agents pourra prendre un certain temps.", "xpack.apm.agentConfig.deleteSection.deleteConfigSucceededTitle": "La configuration a été supprimée", - "xpack.apm.agentConfig.disableInstrumentations.description": "Liste séparée par des virgules de modules pour lesquels désactiver l'instrumentation.\nLorsque l'instrumentation est désactivée pour un module, aucun intervalle n'est collecté pour ce module.\n\nLa liste à jour des modules pour lesquels l'instrumentation peut être désactivée est spécifique du langage et peut être trouvée en cliquant sur les liens suivants : [Java](https://www.elastic.co/guide/en/apm/agent/java/current/config-core.html#config-disable-instrumentations)", + "xpack.apm.agentConfig.disableInstrumentations.description": "Liste séparée par des virgules de modules pour lesquels désactiver l'instrumentation. Lorsque l'instrumentation est désactivée pour un module, aucun intervalle n'est collecté pour ce module. La liste à jour des modules pour lesquels l'instrumentation peut être désactivée est spécifique du langage et peut être trouvée en cliquant sur les liens suivants : [Java](https://www.elastic.co/guide/en/apm/agent/java/current/config-core.html#config-disable-instrumentations)", "xpack.apm.agentConfig.disableInstrumentations.label": "Désactiver les instrumentations", - "xpack.apm.agentConfig.disableOutgoingTracecontextHeaders.description": "Utilisez cette option pour désactiver l'injection d'en-têtes `tracecontext` dans une communication sortante.\n\nAVERTISSEMENT : La désactivation de l'injection d'en-têtes `tracecontext` signifie que le traçage distribué ne fonctionnera pas sur les services en aval.", + "xpack.apm.agentConfig.disableOutgoingTracecontextHeaders.description": "Utilisez cette option pour désactiver l'injection d'en-têtes `tracecontext` dans une communication sortante. AVERTISSEMENT : La désactivation de l'injection d'en-têtes `tracecontext` signifie que le traçage distribué ne fonctionnera pas sur les services en aval.", "xpack.apm.agentConfig.disableOutgoingTracecontextHeaders.label": "Désactiver les en-têtes tracecontext sortants", "xpack.apm.agentConfig.editConfigTitle": "Modifier la configuration", - "xpack.apm.agentConfig.enableExperimentalInstrumentations.description": "Indique s'il faut appliquer des instrumentations expérimentales.\n\nREMARQUE : Le fait de modifier cette valeur au moment de l'exécution peut ralentir temporairement l'application. Définir cette valeur sur true active les instrumentations dans le groupe expérimental.", + "xpack.apm.agentConfig.enableExperimentalInstrumentations.description": "Indique s'il faut appliquer des instrumentations expérimentales. REMARQUE : Le fait de modifier cette valeur au moment de l'exécution peut ralentir temporairement l'application. Définir cette valeur sur true active les instrumentations dans le groupe expérimental.", "xpack.apm.agentConfig.enableExperimentalInstrumentations.label": "Activer les instrumentations expérimentales", - "xpack.apm.agentConfig.enableInstrumentations.description": "Une liste des instrumentations qui doivent être activées de façon sélective. Les options valides sont indiquées dans la [documentation de l’agent Java APM](https://www.elastic.co/guide/en/apm/agent/java/current/config-core.html#config-disable-instrumentations).\n\nLorsqu'une valeur non vide est définie, seules les instrumentations répertoriées sont activées si elles ne sont pas désactivées via `disable_instrumentations` ou `enable_experimental_instrumentations`.\nLorsque cette option n'est pas définie ou est vide (par défaut), toutes les instrumentations activées par défaut sont activées, sauf si elles sont désactivées via `disable_instrumentations` ou `enable_experimental_instrumentations`.", + "xpack.apm.agentConfig.enableInstrumentations.description": "Une liste des instrumentations qui doivent être activées de façon sélective. Les options valides sont indiquées dans la [documentation de l’agent Java APM](https://www.elastic.co/guide/en/apm/agent/java/current/config-core.html#config-disable-instrumentations). Lorsqu'une valeur non vide est définie, seules les instrumentations répertoriées sont activées si elles ne sont pas désactivées via `disable_instrumentations` ou `enable_experimental_instrumentations`. Lorsque cette option n'est pas définie ou est vide (par défaut), toutes les instrumentations activées par défaut sont activées, sauf si elles sont désactivées via `disable_instrumentations` ou `enable_experimental_instrumentations`.", "xpack.apm.agentConfig.enableInstrumentations.label": "Désactiver les instrumentations", "xpack.apm.agentConfig.enableLogCorrelation.description": "Nombre booléen spécifiant si l'agent doit être intégré au MDC de SLF4J pour activer la corrélation de logs de suivi. Si cette option est configurée sur `true`, l'agent définira `trace.id` et `transaction.id` pour les intervalles et transactions actifs sur le MDC. Depuis la version 1.16.0 de l'agent Java, l'agent ajoute également le `error.id` de l'erreur capturée au MDC juste avant le logging du message d'erreur. REMARQUE : bien qu'il soit autorisé d'activer ce paramètre au moment de l'exécution, vous ne pouvez pas le désactiver sans redémarrage.", "xpack.apm.agentConfig.enableLogCorrelation.label": "Activer la corrélation de logs", - "xpack.apm.agentConfig.exitSpanMinDuration.description": "Les intervalles de sortie sont des intervalles qui représentent un appel à un service externe, tel qu'une base de données. Si de tels appels sont très courts, ils ne sont généralement pas pertinents et ils peuvent être ignorés.\n\nREMARQUE : Si un intervalle propage des ID de traçage distribué, il ne sera pas ignoré, même s'il est plus court que le seuil configuré. Cela permet de s'assurer qu'aucune trace interrompue n'est enregistrée.", + "xpack.apm.agentConfig.exitSpanMinDuration.description": "Les intervalles de sortie sont des intervalles qui représentent un appel à un service externe, tel qu'une base de données. Si de tels appels sont très courts, ils ne sont généralement pas pertinents et ils peuvent être ignorés. REMARQUE : Si un intervalle propage des ID de traçage distribué, il ne sera pas ignoré, même s'il est plus court que le seuil configuré. Cela permet de s'assurer qu'aucune trace interrompue n'est enregistrée.", "xpack.apm.agentConfig.exitSpanMinDuration.label": "Durée min. d'intervalle de sortie", - "xpack.apm.agentConfig.ignoreExceptions.description": "Liste d'exceptions qui doivent être ignorées et non signalées comme des erreurs.\nCela permet d'ignorer les exceptions qui ont été lancées dans le flux de contrôle normal mais qui ne sont pas de réelles erreurs.", + "xpack.apm.agentConfig.ignoreExceptions.description": "Liste d'exceptions qui doivent être ignorées et non signalées comme des erreurs. Cela permet d'ignorer les exceptions qui ont été lancées dans le flux de contrôle normal mais qui ne sont pas de réelles erreurs.", "xpack.apm.agentConfig.ignoreExceptions.label": "Ignorer les exceptions", - "xpack.apm.agentConfig.ignoreMessageQueues.description": "Utilisé pour exclure les files d'attente/sujets de messagerie spécifiques du traçage. \n\nCette propriété doit être définie sur un tableau contenant une ou plusieurs chaînes.\nUne fois définie, les envois vers et les réceptions depuis les files d'attente/sujets spécifiés seront ignorés.", + "xpack.apm.agentConfig.ignoreMessageQueues.description": "Utilisé pour exclure les files d'attente/sujets de messagerie spécifiques du traçage. Cette propriété doit être définie sur un tableau contenant une ou plusieurs chaînes. Une fois définie, les envois vers et les réceptions depuis les files d'attente/sujets spécifiés seront ignorés.", "xpack.apm.agentConfig.ignoreMessageQueues.label": "Ignorer les files d'attente des messages", "xpack.apm.agentConfig.logEcsReformatting.description": "Spécifier si et comment l'agent doit reformater automatiquement les logs d'application en [JSON compatible avec ECS](https://www.elastic.co/guide/en/ecs-logging/overview/master/intro.html), compatible avec l'ingestion dans Elasticsearch à des fins d'analyse de log plus poussée.", "xpack.apm.agentConfig.logEcsReformatting.label": "Reformatage ECS des logs", "xpack.apm.agentConfig.logLevel.description": "Définit le niveau de logging pour l'agent", "xpack.apm.agentConfig.logLevel.label": "Niveau du log", - "xpack.apm.agentConfig.logSending.description": "Expérimental, requiert la version la plus récente de l'agent Java.\n\nSi `true` est défini,\nL'agent envoie les logs directement au serveur APM.", + "xpack.apm.agentConfig.logSending.description": "Expérimental, requiert la version la plus récente de l'agent Java. Si défini sur `true`, l'agent enverra les logs directement au serveur APM.", "xpack.apm.agentConfig.logSending.label": "Envoi de logs (expérimental)", - "xpack.apm.agentConfig.mongodbCaptureStatementCommands.description": "Les noms de commande MongoDB pour lesquels le document de commande est capturé, limité aux opérations en lecture seule courantes par défaut. Définissez cette option sur `\"\"` (vide) pour désactiver la capture, et sur `*` pour tout capturer (ce qui est déconseillé, car cela peut entraîner la capture d'informations sensibles).\n\nCette option prend en charge le caractère générique `*` qui correspond à zéro caractère ou plus. Exemples : `/foo/*/bar/*/baz*`, `*foo*`. La correspondance n'est pas sensible à la casse par défaut. L'ajout de `(?-i)` au début d'un élément rend la correspondance sensible à la casse.", + "xpack.apm.agentConfig.mongodbCaptureStatementCommands.description": "Les noms de commande MongoDB pour lesquels le document de commande est capturé, limité aux opérations en lecture seule courantes par défaut. Définissez cette option sur `\"\"` (vide) pour désactiver la capture, et sur `*` pour tout capturer (ce qui est déconseillé, car cela peut entraîner la capture d'informations sensibles). Cette option prend en charge le caractère générique `*` qui correspond à zéro caractère ou plus. Exemples : `/foo/*/bar/*/baz*`, `*foo*`. La correspondance n'est pas sensible à la casse par défaut. L'ajout de `(?-i)` au début d'un élément rend la correspondance sensible à la casse.", "xpack.apm.agentConfig.mongodbCaptureStatementCommands.label": "Commandes d'instruction pour la capture MongoDB", "xpack.apm.agentConfig.newConfig.description": "Affinez votre configuration d'agent depuis l'application APM. Les modifications sont automatiquement propagées à vos agents APM, ce qui vous évite d'effectuer un redéploiement.", "xpack.apm.agentConfig.profilingInferredSpansEnabled.description": "Définissez cette option sur `true` afin que l'agent crée des intervalles pour des exécutions de méthodes basées sur async-profiler, un profiler d'échantillonnage (ou profiler statistique). En raison de la nature du fonctionnement des profilers d'échantillonnage, la durée des intervalles générés n'est pas exacte, il ne s'agit que d'estimations. `profiling_inferred_spans_sampling_interval` vous permet d'ajuster avec exactitude le compromis entre précision et surcharge. Les intervalles générés sont créés à la fin d'une session de profilage. Cela signifie qu'il existe un délai entre les intervalles réguliers et les intervalles générés visibles dans l'interface utilisateur. REMARQUE : cette fonctionnalité n'est pas disponible sous Windows.", @@ -9892,7 +10712,7 @@ "xpack.apm.agentConfig.profilingInferredSpansMinDuration.label": "Durée minimale des intervalles générés par le profilage", "xpack.apm.agentConfig.profilingInferredSpansSamplingInterval.description": "Fréquence à laquelle les traces de pile sont rassemblées au cours d'une session de profilage. Plus vous définissez un chiffre bas, plus les durées seront précises. Cela induit une surcharge plus élevée et un plus grand nombre d'intervalles, pour des opérations potentiellement non pertinentes. La durée minimale d'un intervalle généré par le profilage est identique à la valeur de ce paramètre.", "xpack.apm.agentConfig.profilingInferredSpansSamplingInterval.label": "Intervalle d'échantillonnage des intervalles générés par le profilage", - "xpack.apm.agentConfig.range.errorText": "{rangeType, select,\n between {doit être compris entre {min} et {max}}\n gt {doit être supérieur à {min}}\n lt {doit être inférieur à {max}}\n other {doit être un entier}\n }", + "xpack.apm.agentConfig.range.errorText": "{rangeType, select, between {Doit être compris entre {min} et {max}} gt {Doit être supérieur à {min}} lt {Doit être inférieur à {max}} other {Doit être un entier} }", "xpack.apm.agentConfig.recording.description": "Lorsque l'enregistrement est activé, l'agent instrumente les requêtes HTTP entrantes, effectue le suivi des erreurs, et collecte et envoie les indicateurs. Lorsque l'enregistrement n'est pas activé, l'agent agit comme un noop, sans collecter de données ni communiquer avec le serveur AMP, sauf pour rechercher la configuration mise à jour. Puisqu'il s'agit d'un commutateur réversible, les threads d'agents ne sont pas détruits lorsque le mode sans enregistrement est défini. Ils restent principalement inactifs, de sorte que la surcharge est négligeable. Vous pouvez utiliser ce paramètre pour contrôler dynamiquement si Elastic APM doit être activé ou désactivé.", "xpack.apm.agentConfig.recording.label": "Enregistrement", "xpack.apm.agentConfig.sanitizeFiledNames.description": "Il est parfois nécessaire d'effectuer un nettoyage, c'est-à-dire de supprimer les données sensibles envoyées à Elastic APM. Cette configuration accepte une liste de modèles de caractères génériques de champs de noms qui doivent être nettoyés. Ils s'appliquent aux en-têtes HTTP (y compris les cookies) et aux données `application/x-www-form-urlencoded` (champs de formulaire POST). La chaîne de la requête et le corps de la requête capturé (comme des données `application/json`) ne seront pas nettoyés.", @@ -9902,7 +10722,7 @@ "xpack.apm.agentConfig.saveConfig.succeeded.text": "La configuration de \"{serviceName}\" a été enregistrée. La propagation jusqu'aux agents pourra prendre un certain temps.", "xpack.apm.agentConfig.saveConfig.succeeded.title": "Configuration enregistrée", "xpack.apm.agentConfig.saveConfigurationButtonLabel": "Étape suivante", - "xpack.apm.agentConfig.serverTimeout.description": "Si une requête au serveur APM prend plus de temps que le délai d'expiration configuré,\nla requête est annulée et l'événement (exception ou transaction) est abandonné.\nDéfinissez sur 0 pour désactiver les délais d'expiration.\n\nAVERTISSEMENT : si les délais d'expiration sont désactivés ou définis sur une valeur élevée, il est possible que votre application rencontre des problèmes de mémoire en cas d'expiration du serveur APM.", + "xpack.apm.agentConfig.serverTimeout.description": "Si une requête adressée au serveur APM prend plus de temps que le délai d'expiration configuré, la requête est annulée et l'événement (exception ou transaction) est ignoré. Définissez sur 0 pour désactiver les délais d'expiration. AVERTISSEMENT : si les délais d'expiration sont désactivés ou définis sur une valeur élevée, il est possible que votre application rencontre des problèmes de mémoire en cas d'expiration du serveur APM.", "xpack.apm.agentConfig.serverTimeout.label": "Délai d'expiration du serveur", "xpack.apm.agentConfig.servicePage.alreadyConfiguredOption": "déjà configuré", "xpack.apm.agentConfig.servicePage.cancelButton": "Annuler", @@ -9919,17 +10739,17 @@ "xpack.apm.agentConfig.settingsPage.notFound.message": "La configuration demandée n'existe pas", "xpack.apm.agentConfig.settingsPage.notFound.title": "Désolé, une erreur est survenue", "xpack.apm.agentConfig.settingsPage.saveButton": "Enregistrer la configuration", - "xpack.apm.agentConfig.spanCompressionEnabled.description": "L'attribution de la valeur \"true\" à cette option activera la fonctionnalité de compression de l'intervalle.\nLa compression d'intervalle réduit la surcharge de collecte, de traitement et de stockage, et supprime l'encombrement dans l'interface utilisateur. Le compromis est que certaines informations, telles que les instructions de base de données de tous les intervalles compressés, ne seront pas collectées.", + "xpack.apm.agentConfig.spanCompressionEnabled.description": "L'attribution de la valeur \"true\" à cette option activera la fonctionnalité de compression de l'intervalle. La compression d'intervalle réduit la surcharge de collecte, de traitement et de stockage, et supprime l'encombrement dans l'interface utilisateur. Le compromis est que certaines informations, telles que les instructions de base de données de tous les intervalles compressés, ne seront pas collectées.", "xpack.apm.agentConfig.spanCompressionEnabled.label": "Compression d'intervalle activée", "xpack.apm.agentConfig.spanCompressionExactMatchMaxDuration.description": "Les intervalles consécutifs qui sont des correspondances parfaites et qui se trouvent sous ce seuil seront compressés en un seul intervalle composite. Cette option ne s'applique pas aux intervalles composites. Cela réduit la surcharge de collecte, de traitement et de stockage, et supprime l'encombrement dans l'interface utilisateur. Le compromis est que les instructions de base de données de tous les intervalles compressés ne seront pas collectées.", "xpack.apm.agentConfig.spanCompressionExactMatchMaxDuration.label": "Durée maximale de compression d'intervalles en correspondance parfaite", "xpack.apm.agentConfig.spanCompressionSameKindMaxDuration.description": "Les intervalles consécutifs qui ont la même destination et qui se trouvent sous ce seuil seront compressés en un seul intervalle composite. Cette option ne s'applique pas aux intervalles composites. Cela réduit la surcharge de collecte, de traitement et de stockage, et supprime l'encombrement dans l'interface utilisateur. Le compromis est que les instructions de base de données de tous les intervalles compressés ne seront pas collectées.", "xpack.apm.agentConfig.spanCompressionSameKindMaxDuration.label": "Durée maximale de compression d'intervalles de même genre", - "xpack.apm.agentConfig.spanFramesMinDuration.description": "(déclassé, utilisez `span_stack_trace_min_duration` à la place) Dans ses paramètres par défaut, l'agent APM collectera une trace de la pile avec chaque intervalle enregistré.\nBien qu'il soit très pratique de trouver l'endroit exact dans votre code qui provoque l'intervalle, la collecte de cette trace de la pile provoque une certaine surcharge. \nLorsque cette option est définie sur une valeur négative, telle que `-1ms`, les traces de pile sont collectées pour tous les intervalles. En choisissant une valeur positive, par ex. `5ms`, la collecte des traces de pile se limitera aux intervalles dont la durée est égale ou supérieure à la valeur donnée, c’est-à-dire 5 millisecondes.\n\nPour désactiver complètement la collecte des traces de pile des intervalles, réglez la valeur sur `0ms`.", + "xpack.apm.agentConfig.spanFramesMinDuration.description": "(déclassé, utilisez `span_stack_trace_min_duration` à la place) Dans ses paramètres par défaut, l'agent APM collectera une trace de la pile avec chaque intervalle enregistré. Bien qu'il soit très pratique de trouver l'endroit exact dans votre code qui provoque l'intervalle, la collecte de cette trace de la pile provoque une certaine surcharge. Lorsque cette option est définie sur une valeur négative, telle que `-1ms`, les traces de pile sont collectées pour tous les intervalles. En choisissant une valeur positive, par ex. `5ms`, la collecte des traces de pile se limitera aux intervalles dont la durée est égale ou supérieure à la valeur donnée, c’est-à-dire 5 millisecondes. Pour désactiver complètement la collecte des traces de pile des intervalles, réglez la valeur sur `0ms`.", "xpack.apm.agentConfig.spanFramesMinDuration.label": "Durée minimale des cadres des intervalles", - "xpack.apm.agentConfig.spanMinDuration.description": "Définit la durée minimale des intervalles. Une tentative visant à ignorer les intervalles qui s'exécutent plus rapidement que ce seuil peut avoir lieu.\n\nLa tentative échoue si elle mène à un intervalle qui ne peut pas être ignoré. Les intervalles qui propagent le contexte de trace aux services en aval, tels que les requêtes HTTP sortantes, ne peuvent pas être ignorés. De plus, les intervalles qui conduisent à une erreur ou qui peuvent être le parent d'une opération asynchrone ne peuvent pas être ignorés.\n\nCependant, les appels externes qui ne propagent pas le contexte, tels que les appels à une base de données, peuvent être ignorés à l'aide de ce seuil.", + "xpack.apm.agentConfig.spanMinDuration.description": "Définit la durée minimale des intervalles. Une tentative visant à ignorer les intervalles qui s'exécutent plus rapidement que ce seuil peut avoir lieu. La tentative échoue si elle mène à un intervalle qui ne peut pas être ignoré. Les intervalles qui propagent le contexte de trace aux services en aval, tels que les requêtes HTTP sortantes, ne peuvent pas être ignorés. De plus, les intervalles qui conduisent à une erreur ou qui peuvent être le parent d'une opération asynchrone ne peuvent pas être ignorés. Cependant, les appels externes qui ne propagent pas le contexte, tels que les appels à une base de données, peuvent être ignorés à l'aide de ce seuil.", "xpack.apm.agentConfig.spanMinDuration.label": "Durée minimale de l'intervalle", - "xpack.apm.agentConfig.spanStackTraceMinDuration.description": "Bien qu'il soit très pratique de trouver l'endroit exact dans votre code qui provoque l'intervalle, la collecte de cette trace de la pile provoque une certaine surcharge. Lorsque cette option est définie sur la valeur `0ms`, les traces de pile sont collectées pour tous les intervalles. En choisissant une valeur positive, par ex. `5ms`, la collecte des traces de pile se limitera aux intervalles dont la durée est égale ou supérieure à la valeur donnée, c’est-à-dire 5 millisecondes.\n\nPour désactiver complètement la collecte des traces de pile des intervalles, réglez la valeur sur `-1ms`.", + "xpack.apm.agentConfig.spanStackTraceMinDuration.description": "Bien qu'il soit très pratique de trouver l'endroit exact dans votre code qui provoque l'intervalle, la collecte de cette trace de la pile provoque une certaine surcharge. Lorsque cette option est définie sur la valeur `0ms`, les traces de pile sont collectées pour tous les intervalles. En choisissant une valeur positive, par ex. `5ms`, la collecte des traces de pile se limitera aux intervalles dont la durée est égale ou supérieure à la valeur donnée, c’est-à-dire 5 millisecondes. Pour désactiver complètement la collecte des traces de pile des intervalles, réglez la valeur sur `-1ms`.", "xpack.apm.agentConfig.spanStackTraceMinDuration.label": "Durée minimale de la trace de pile de l'intervalle", "xpack.apm.agentConfig.stackTraceLimit.description": "En définissant cette option sur 0, la collecte des traces de pile sera désactivée. Toute valeur entière positive sera utilisée comme nombre maximal de cadres à collecter. La valeur -1 signifie que tous les cadres seront collectés.", "xpack.apm.agentConfig.stackTraceLimit.label": "Limite de trace de pile", @@ -9943,24 +10763,24 @@ "xpack.apm.agentConfig.stressMonitorSystemCpuReliefThreshold.label": "Seuil d'allègement de la tension du monitoring du CPU système", "xpack.apm.agentConfig.stressMonitorSystemCpuStressThreshold.description": "Seuil utilisé par le monitoring du CPU du système pour détecter la tension du processeur du système. Si le CPU système dépasse ce seuil pour une durée d'au moins `stress_monitor_cpu_duration_threshold`, le monitoring considère qu'il est en état de tension.", "xpack.apm.agentConfig.stressMonitorSystemCpuStressThreshold.label": "Seuil de tension du monitoring du CPU système", - "xpack.apm.agentConfig.traceContinuationStrategy.description": "Cette option permet un certain contrôle sur la façon dont l'agent APM gère les en-tête de contexte de trace W3C dans les requêtes entrantes. Par défaut, les en-têtes `traceparent` et `tracestate` sont utilisés conformément aux spécifications W3C pour le traçage distribué. Cependant, dans certains cas, il peut être utile de ne pas utiliser l'en-tête `traceparent` entrant. Quelques exemples de cas d'utilisation :\n\n* Un service monitoré par Elastic reçoit des requêtes avec les en-têtes `traceparent` de services non monitorés.\n* Un service monitoré par Elastic est publiquement exposé, et ne souhaite pas que les données de traçage (ID de traçage, décisions d'échantillonnage) puissent être usurpées par des requêtes d'utilisateur.\n\nLes valeurs valides sont :\n* \"continue\" : comportement par défaut. Une valeur `traceparent` entrante est utilisée pour continuer le traçage et déterminer la décision d'échantillonnage.\n* \"restart\" : ignore toujours l'en-tête `traceparent` des requêtes entrantes. Un nouveau trace-id sera généré et la décision d'échantillonnage sera prise en fonction de transaction_sample_rate. Une liaison d'intervalle sera effectuée vers le `traceparent` entrant.\n* \"restart_external\" : Si une requête entrante inclut le drapeau de fournisseur `es` dans `tracestate`, tout `traceparent` sera considéré comme interne et sera géré comme décrit pour `continue` ci-dessus. Autrement, tout `traceparent` est considéré comme externe et sera géré comme décrit pour `restart` ci-dessus.\n\nDepuis Elastic Observability 8.2, les liens d'intervalle sont visibles dans les vues de trace.\n\nCette option ne respecte pas la casse.", + "xpack.apm.agentConfig.traceContinuationStrategy.description": "Cette option permet un certain contrôle sur la façon dont l'agent APM gère les en-tête de contexte de trace W3C dans les requêtes entrantes. Par défaut, les en-têtes `traceparent` et `tracestate` sont utilisés conformément aux spécifications W3C pour le traçage distribué. Cependant, dans certains cas, il peut être utile de ne pas utiliser l'en-tête `traceparent` entrant. Quelques exemples de cas d'utilisation : * Un service monitoré par Elastic reçoit des requêtes avec les en-têtes `traceparent` de services non monitorés. * Un service monitoré par Elastic est publiquement exposé, et ne souhaite pas que les données de traçage (ID de traçage, décisions d'échantillonnage) puissent être usurpées par des requêtes d'utilisateur. Les valeurs valides sont : * 'continue' : comportement par défaut. Une valeur `traceparent` entrante est utilisée pour continuer le traçage et déterminer la décision d'échantillonnage. * 'restart' : ignore toujours l'en-tête `traceparent` des requêtes entrantes. Un nouveau trace-id sera généré et la décision d'échantillonnage sera prise en fonction de transaction_sample_rate. Une liaison d'intervalle sera effectuée vers le `traceparent` entrant. * 'restart_external' : Si une requête entrante inclut le drapeau de fournisseur `es` dans `tracestate`, tout `traceparent` sera considéré comme interne et sera géré comme décrit pour `continue` ci-dessus. Autrement, tout `traceparent` est considéré comme externe et sera géré comme décrit pour `restart` ci-dessus. Depuis Elastic Observability 8.2, les liens d'intervalle sont visibles dans les vues de trace. Cette option ne respecte pas la casse.", "xpack.apm.agentConfig.traceContinuationStrategy.label": "Stratégie de poursuite de traçage", - "xpack.apm.agentConfig.traceMethods.description": "Liste de méthodes pour lesquelles une transaction ou un intervalle doivent être créés.\n\nSi vous souhaitez monitorer un nombre important de méthodes,\nutilisez `profiling_inferred_spans_enabled`.\n\nCela fonctionne en instrumentant chaque méthode correspondante pour inclure le code qui crée un intervalle pour la méthode.\nSi la création d'un intervalle est très économique en termes de performances,\nl'instrumentation de toute une base de codes ou d'une méthode qui est exécutée dans une boucle serrée entraîne une surcharge significative.\n\nREMARQUE : utilisez les caractères génériques uniquement si cela est nécessaire.\nPlus vous faites correspondre de méthodes, plus l'agent créera une surcharge.\nNotez également qu'il existe une quantité maximale d'intervalles par transaction, `transaction_max_spans`.\n\nPour en savoir plus, consultez la documentation de l'agent Java.", + "xpack.apm.agentConfig.traceMethods.description": "Liste de méthodes pour lesquelles une transaction ou un intervalle doivent être créés. Si vous souhaitez monitorer un nombre important de méthodes, utilisez `profiling_inferred_spans_enabled`. Cela fonctionne en instrumentant chaque méthode correspondante pour inclure le code qui crée un intervalle pour la méthode. Alors que la création d'un intervalle est très économique en termes de performances, l'instrumentation de toute une base de codes ou d'une méthode qui est exécutée dans une boucle serrée entraîne une surcharge significative. REMARQUE : utilisez les caractères génériques uniquement si cela est nécessaire. Plus vous faites correspondre de méthodes, plus l'agent créera une surcharge. Notez également qu'il existe une quantité maximale d'intervalles par transaction, `transaction_max_spans`. Pour en savoir plus, consultez la documentation de l'agent Java.", "xpack.apm.agentConfig.traceMethods.label": "Méthodes de traçage", "xpack.apm.agentConfig.transactionIgnoreUrl.description": "Utilisé pour limiter l'instrumentation des requêtes vers certaines URL. Cette configuration accepte une liste séparée par des virgules de modèles de caractères génériques de chemins d'URL qui doivent être ignorés. Lorsqu'une requête HTTP entrante sera détectée, son chemin de requête sera confronté à chaque élément figurant dans cette liste. Par exemple, l'ajout de `/home/index` à cette liste permettrait de faire correspondre et de supprimer l'instrumentation de `http://localhost/home/index` ainsi que de `http://whatever.com/home/index?value1=123`", "xpack.apm.agentConfig.transactionIgnoreUrl.label": "Ignorer les transactions basées sur les URL", - "xpack.apm.agentConfig.transactionIgnoreUserAgents.description": "Utilisé pour limiter l'instrumentation des requêtes de certains agents utilisateurs.\n\nLorsqu'une requête HTTP entrante est détectée,\nl'agent utilisateur des en-têtes de la requête sera testé avec chaque élément de cette liste.\nExemple : `curl/*`, `*pingdom*`", + "xpack.apm.agentConfig.transactionIgnoreUserAgents.description": "Utilisé pour limiter l'instrumentation des requêtes de certains agents utilisateurs. Lorsqu'une requête HTTP entrante est détectée, l'agent utilisateur des en-têtes de requête sera vérifié par rapport à chaque élément de cette liste. Exemple : `curl/*`, `*pingdom*`", "xpack.apm.agentConfig.transactionIgnoreUserAgents.label": "La transaction ignore les agents utilisateurs", "xpack.apm.agentConfig.transactionMaxSpans.description": "Limite la quantité d'intervalles enregistrés par transaction.", "xpack.apm.agentConfig.transactionMaxSpans.label": "Nb maxi d'intervalles de transaction", - "xpack.apm.agentConfig.transactionNameGroups.description": "Avec cette option,\nvous pouvez regrouper les noms de transaction contenant des parties dynamiques avec une expression de caractère générique.\nPar exemple,\nle modèle \"GET /user/*/cart\" consolide les transactions,\ntelles que \"GET /users/42/cart\" et \"GET /users/73/cart\", en un même nom de transaction, \"GET /users/*/cart\",\nréduisant ainsi la cardinalité du nom de transaction.", + "xpack.apm.agentConfig.transactionNameGroups.description": "Avec cette option, vous pouvez regrouper les noms de transaction contenant des parties dynamiques avec une expression de caractère générique. Par exemple, le modèle `GET /user/*/cart` consoliderait les transactions telles que `GET /users/42/cart` et `GET /users/73/cart` en un seul nom de transaction `GET /users/*/cart`, réduisant ainsi la cardinalité du nom de transaction.", "xpack.apm.agentConfig.transactionNameGroups.label": "Groupes de noms de transaction", "xpack.apm.agentConfig.transactionSampleRate.description": "Par défaut, l'agent échantillonnera chaque transaction (par ex. requête à votre service). Pour réduire la surcharge et les exigences de stockage, vous pouvez définir le taux d'échantillonnage sur une valeur comprise entre 0,0 et 1,0. La durée globale et le résultat des transactions non échantillonnées seront toujours enregistrés, mais pas les informations de contexte, les étiquettes ni les intervalles.", "xpack.apm.agentConfig.transactionSampleRate.label": "Taux d'échantillonnage des transactions", - "xpack.apm.agentConfig.unnestExceptions.description": "Lors du reporting d'exceptions,\ndésimbrique les exceptions correspondant au modèle de caractère générique.\nCela peut s'avérer pratique pour Spring avec \"org.springframework.web.util.NestedServletException\",\npar exemple.", + "xpack.apm.agentConfig.unnestExceptions.description": "Lors du reporting d'exceptions, désimbrique les exceptions correspondant au modèle de caractère générique. Par exemple, cela peut s'avérer pratique pour Spring avec `org.springframework.web.util.NestedServletException`.", "xpack.apm.agentConfig.unnestExceptions.label": "Désimbriquer les exceptions", "xpack.apm.agentConfig.unsavedSetting.tooltip": "Non enregistré", - "xpack.apm.agentConfig.usePathAsTransactionName.description": "Si `true` est défini,\nles noms de transaction de frameworks non pris en charge ou partiellement pris en charge seront au format `$method $path` au lieu de simplement `$method unknown route`.\n\nAVERTISSEMENT : si vos URL contiennent des paramètres de chemin tels que `/user/$userId`,\nsoyez très prudent en activant cet indicateur,\ncar cela peut entraîner une explosion de groupes de transactions.\nConsultez l'option `transaction_name_groups` pour savoir comment atténuer ce problème en regroupant les URL ensemble.", + "xpack.apm.agentConfig.usePathAsTransactionName.description": "Lorsque défini sur `true`, les noms de transaction de frameworks non pris en charge ou partiellement pris en charge seront au format `$method $path` au lieu de simplement `$method unknown route`. AVERTISSEMENT : Si vos URL contiennent des paramètres de chemin tels que `/user/$userId`, vous devez être très prudent lorsque vous activez cet indicateur, car cela peut entraîner une explosion des groupes de transactions. Consultez l'option `transaction_name_groups` pour savoir comment atténuer ce problème en regroupant les URL ensemble.", "xpack.apm.agentConfig.usePathAsTransactionName.label": "Utiliser le chemin comme nom de transaction", "xpack.apm.agentExplorer.agentLanguageSelect.label": "Langage de l'agent", "xpack.apm.agentExplorer.agentLanguageSelect.placeholder": "Tous", @@ -10028,13 +10848,14 @@ "xpack.apm.aiAssistant.starterPrompts.explainNoData.title": "Expliquer", "xpack.apm.alertDetails.error.toastDescription": "Impossible de charger les graphiques de la page de détails d’alerte. Veuillez essayer d’actualiser la page si l’alerte vient d’être créée", "xpack.apm.alertDetails.error.toastTitle": "Une erreur s’est produite lors de l’identification de la plage temporelle de l’alerte.", + "xpack.apm.alertDetails.thresholdTitle": "Seuil dépassé", "xpack.apm.alertDetails.viewInApm": "Afficher dans APM", "xpack.apm.alerting.fields.environment": "Environnement", "xpack.apm.alerting.fields.error.group.id": "Clé du groupe d'erreurs", "xpack.apm.alerting.fields.service": "Service", "xpack.apm.alerting.fields.transaction.name": "Nom", "xpack.apm.alerting.fields.type": "Type", - "xpack.apm.alerting.transaction.name.custom.text": "Ajouter \\{searchValue\\} en tant que nouveau nom de transaction", + "xpack.apm.alerting.transaction.name.custom.text": "Ajouter '{searchValue}' en tant que nouveau nom de transaction", "xpack.apm.alertingEmbeddables.serviceName.error.toastDescription": "Impossible de charger les visualisations d’APM.", "xpack.apm.alertingEmbeddables.serviceName.error.toastTitle": "Une erreur s'est produite lors de l'identification du nom du service APM ou du type de transaction.", "xpack.apm.alertingEmbeddables.timeRange.error.toastTitle": "Une erreur s’est produite lors de l’identification de la plage temporelle de l’alerte.", @@ -10068,20 +10889,20 @@ "xpack.apm.alerts.timeLabels.minutes": "minutes", "xpack.apm.alerts.timeLabels.seconds": "secondes", "xpack.apm.alertTypes.anomaly.description": "Alerte lorsque la latence, le rendement ou le taux de transactions ayant échoué d'un service est anormal.", - "xpack.apm.alertTypes.errorCount.defaultActionMessage": "'{{context.reason}}'\n\n'{{rule.name}}' est active selon les conditions suivantes :\n\n- Nom de service : '{{context.serviceName}}'\n- Environnement : '{{context.environment}}'\n- Nombre d’erreurs : '{{context.triggerValue}}' erreurs sur la dernière période de '{{context.interval}}'\n- Seuil : '{{context.threshold}}'\n\n[Afficher les détails de l’alerte]('{{context.alertDetailsUrl}}')\n", - "xpack.apm.alertTypes.errorCount.defaultRecoveryMessage": "'{{context.reason}}'\n\n'{{rule.name}}' s’est rétablie.\n\n- Nom de service : '{{context.serviceName}}'\n- Environnement : '{{context.environment}}'\n- Nombre d’erreurs : '{{context.triggerValue}}' erreurs sur la dernière période de '{{context.interval}}'\n- Seuil : '{{context.threshold}}'\n\n[Afficher les détails de l’alerte]('{{context.alertDetailsUrl}}')\n", + "xpack.apm.alertTypes.errorCount.defaultActionMessage": "'{{context.reason}}' '{{rule.name}}' est actif avec les conditions suivantes : - Nom du service : '{{context.serviceName}}' - Environnement : '{{context.environment}}' - Nombre d'erreurs : '{{context.triggerValue}}' erreurs au cours des dernières '{{context.interval}}' - Seuil : '{{context.threshold}}' [Afficher les détails de l'alerte]('{{context.alertDetailsUrl}}')", + "xpack.apm.alertTypes.errorCount.defaultRecoveryMessage": "'{{context.reason}}' '{{rule.name}}' s'est rétabli : - Nom du service : '{{context.serviceName}}' - Environnement : '{{context.environment}}' - Nombre d'erreurs : '{{context.triggerValue}}' erreurs au cours des dernières '{{context.interval}}' - Seuil : '{{context.threshold}}' [Afficher les détails de l'alerte]('{{context.alertDetailsUrl}}')", "xpack.apm.alertTypes.errorCount.description": "Alerte lorsque le nombre d'erreurs d'un service dépasse un seuil défini.", "xpack.apm.alertTypes.errorCount.reason": "Le nombre d'erreurs est {measured} au cours des derniers/dernières {interval} pour {group}. Alerte lorsque > {threshold}.", "xpack.apm.alertTypes.minimumWindowSize.description": "La valeur minimale requise est {sizeValue} {sizeUnit}. Elle permet de s'assurer que l'alerte comporte suffisamment de données à évaluer. Si vous choisissez une valeur trop basse, l'alerte ne se déclenchera peut-être pas comme prévu.", - "xpack.apm.alertTypes.transactionDuration.defaultActionMessage": "'{{context.reason}}'\n\n'{{rule.name}}' est active selon les conditions suivantes :\n\n- Nom de service : '{{context.serviceName}}'\n- Type de transaction : '{{context.transactionType}}'\n- Nom de transaction : '{{context.transactionName}}'\n- Environnement : '{{context.environment}}'\n- Latence : '{{context.triggerValue}}' sur la dernière période de '{{context.interval}}'\n- Seuil : '{{context.threshold}}' ms\n\n[Afficher les détails de l’alerte]('{{context.alertDetailsUrl}}')\n", - "xpack.apm.alertTypes.transactionDuration.defaultRecoveryMessage": "'{{context.reason}}'\n\n'{{rule.name}}' s’est rétablie.\n\n- Nom de service : '{{context.serviceName}}'\n- Type de transaction : '{{context.transactionType}}'\n- Nom de transaction : '{{context.transactionName}}'\n- Environnement : '{{context.environment}}'\n- Latence : '{{context.triggerValue}}' sur la dernière période de '{{context.interval}}'\n- Seuil : '{{context.threshold}}' ms\n\n[Afficher les détails de l’alerte]('{{context.alertDetailsUrl}}')\n", + "xpack.apm.alertTypes.transactionDuration.defaultActionMessage": "'{{context.reason}}' '{{rule.name}}' est actif avec les conditions suivantes : - Nom du service : '{{context.serviceName}}' - Type de transaction : '{{context.transactionType}}' - Nom de transaction : '{{context.transactionName}}' - Environnement : '{{context.environment}}' - Latence : '{{context.triggerValue}}' sur les dernières '{{context.interval}}' - Seuil : '{{context.threshold}}' ms [Afficher les détails de l'alerte]('{{context.alertDetailsUrl}}')", + "xpack.apm.alertTypes.transactionDuration.defaultRecoveryMessage": "'{{context.reason}}' '{{rule.name}}' s'est rétabli : - Nom du service : '{{context.serviceName}}' - Type de transaction : '{{context.transactionType}}' - Nom de transaction : '{{context.transactionName}}' - Environnement : '{{context.environment}}' - Latence : '{{context.triggerValue}}' sur les dernières '{{context.interval}}' - Seuil : '{{context.threshold}}' ms [Afficher les détails de l'alerte]('{{context.alertDetailsUrl}}')", "xpack.apm.alertTypes.transactionDuration.description": "Alerte lorsque la latence d'un type de transaction spécifique dans un service dépasse le seuil défini.", "xpack.apm.alertTypes.transactionDuration.reason": "La latence de {aggregationType} est {measured} au cours des derniers/dernières {interval} pour {group}. Alerte lorsque > {threshold}.", - "xpack.apm.alertTypes.transactionDurationAnomaly.defaultActionMessage": "'{{context.reason}}'\n\n'{{rule.name}}' est active selon les conditions suivantes :\n\n- Nom de service : '{{context.serviceName}}'\n- Type de transaction : '{{context.transactionType}}'\n- Environnement : '{{context.environment}}'\n- Sévérité : '{{context.triggerValue}}'\n- Seuil : '{{context.threshold}}'\n\n[Afficher les détails de l’alerte]('{{context.alertDetailsUrl}}')\n", - "xpack.apm.alertTypes.transactionDurationAnomaly.defaultRecoveryMessage": "'{{context.reason}}'\n\n'{{rule.name}}' s’est rétablie.\n\n- Nom de service : '{{context.serviceName}}'\n- Type de transaction : '{{context.transactionType}}'\n- Environnement : '{{context.environment}}'\n- Sévérité : '{{context.triggerValue}}'\n- Seuil : '{{context.threshold}}'\n\n[Afficher les détails de l’alerte]('{{context.alertDetailsUrl}}')\n", + "xpack.apm.alertTypes.transactionDurationAnomaly.defaultActionMessage": "'{{context.reason}}' '{{rule.name}}' est actif avec les conditions suivantes : - Nom du service : '{{context.serviceName}}' - Type de transaction : '{{context.transactionType}}' - Environnement : '{{context.environment}}' - Gravité : '{{context.triggerValue}}' - Seuil : '{{context.threshold}}' [Afficher les détails de l'alerte]('{{context.alertDetailsUrl}}')", + "xpack.apm.alertTypes.transactionDurationAnomaly.defaultRecoveryMessage": "'{{context.reason}}' '{{rule.name}}' s'est rétabli : - Nom du service : '{{context.serviceName}}' - Type de transaction : '{{context.transactionType}}' - Environnement : '{{context.environment}}' - Gravité : '{{context.triggerValue}}' - Seuil : '{{context.threshold}}' [Afficher les détails de l'alerte]('{{context.alertDetailsUrl}}')", "xpack.apm.alertTypes.transactionDurationAnomaly.reason": "Une anomalie {severityLevel} {detectorTypeLabel} avec un score de {anomalyScore} a été détectée dans le dernier {interval} pour {serviceName}.", - "xpack.apm.alertTypes.transactionErrorRate.defaultActionMessage": "'{{context.reason}}'\n\n'{{rule.name}}' est active selon les conditions suivantes :\n\n- Nom de service : '{{context.serviceName}}'\n- Type de transaction : '{{context.transactionType}}'\n- Environnement : '{{context.environment}}'\n- Taux de transactions ayant échoué : '{{context.triggerValue}}' % des erreurs sur la dernière période de '{{context.interval}}'\n- Seuil : '{{context.threshold}}'%\n\n[Afficher les détails de l’alerte]('{{context.alertDetailsUrl}}')\n", - "xpack.apm.alertTypes.transactionErrorRate.defaultRecoveryMessage": "'{{context.reason}}'\n\n'{{rule.name}}' s’est rétablie.\n\n- Nom de service : '{{context.serviceName}}'\n- Type de transaction : '{{context.transactionType}}'\n- Environnement : '{{context.environment}}'\n- Taux de transactions ayant échoué : '{{context.triggerValue}}' % des erreurs sur la dernière période de '{{context.interval}}'\n- Seuil : '{{context.threshold}}'%\n\n[Afficher les détails de l’alerte]('{{context.alertDetailsUrl}}')\n", + "xpack.apm.alertTypes.transactionErrorRate.defaultActionMessage": "'{{context.reason}}' '{{rule.name}}' est actif avec les conditions suivantes : - Nom du service : '{{context.serviceName}}' - Type de transaction : '{{context.transactionType}}' - Environnement : '{{context.environment}}' - Taux de transactions échouées : '{{context.triggerValue}}'% d'erreurs au cours des dernières '{{context.interval}}' - Seuil : '{{context.threshold}}'% [Afficher les détails de l'alerte]('{{context.alertDetailsUrl}}')", + "xpack.apm.alertTypes.transactionErrorRate.defaultRecoveryMessage": "'{{context.reason}}' '{{rule.name}}' s'est rétabli : - Nom du service : '{{context.serviceName}}' - Type de transaction : '{{context.transactionType}}' - Environnement : '{{context.environment}}' - Taux de transactions échouées : '{{context.triggerValue}}'% d'erreurs au cours des dernières '{{context.interval}}' - Seuil : '{{context.threshold}}'% [Afficher les détails de l'alerte]('{{context.alertDetailsUrl}}')", "xpack.apm.alertTypes.transactionErrorRate.description": "Alerte lorsque le taux d'erreurs de transaction d'un service dépasse un seuil défini.", "xpack.apm.alertTypes.transactionErrorRate.reason": "L'échec des transactions est {measured} au cours des derniers/dernières {interval} pour {group}. Alerte lorsque > {threshold}.", "xpack.apm.analyzeDataButton.label": "Explorer les données", @@ -10115,8 +10936,10 @@ "xpack.apm.apmSettings.save.error": "Une erreur s'est produite lors de l'enregistrement des paramètres", "xpack.apm.apmSettings.saveButton": "Enregistrer les modifications", "xpack.apm.appName": "APM", + "xpack.apm.associate.service.logs.button": "Associer les logs de service existants", "xpack.apm.betaBadgeDescription": "Cette fonctionnalité est actuellement en version bêta. Si vous rencontrez des bugs ou si vous souhaitez apporter des commentaires, ouvrez un ticket de problème ou visitez notre forum de discussion.", "xpack.apm.betaBadgeLabel": "Bêta", + "xpack.apm.button.exploreLogs": "Explorer les logs", "xpack.apm.chart.annotation.version": "Version", "xpack.apm.chart.comparison.defaultPreviousPeriodLabel": "Période précédente", "xpack.apm.chart.cpuSeries.processAverageLabel": "Moyenne de processus", @@ -10129,6 +10952,7 @@ "xpack.apm.clickArialLabel.": "Cliquez pour afficher plus de détails", "xpack.apm.coldstartRate": "Taux de démarrage à froid", "xpack.apm.coldstartRate.chart.coldstartRate": "Taux de démarrage à froid (moy.)", + "xpack.apm.collect.service.logs.button": "Collecter de nouveaux logs de service", "xpack.apm.comparison.expectedBoundsTitle": "Limites attendues", "xpack.apm.comparison.mlExpectedBoundsDisabledText": "Limites attendues (la détection d'anomalie doit être activée pour l’environnement)", "xpack.apm.comparison.mlExpectedBoundsText": "Limites attendues", @@ -10277,14 +11101,21 @@ "xpack.apm.durationDistributionChartWithScrubber.emptySelectionText": "Glisser et déposer pour sélectionner une plage", "xpack.apm.durationDistributionChartWithScrubber.panelTitle": "Distribution de la latence", "xpack.apm.durationDistributionChartWithScrubber.selectionText": "Selection : {formattedSelection}", + "xpack.apm.eemFeedback.button.openSurvey": "Dites-nous ce que vous pensez !", + "xpack.apm.eemFeedback.title": "Faites-nous part de vos réflexions !", "xpack.apm.emptyMessage.noDataFoundDescription": "Essayez avec une autre plage temporelle ou réinitialisez le filtre de recherche.", "xpack.apm.emptyMessage.noDataFoundLabel": "Aucune donnée trouvée.", - "xpack.apm.environmentsSelectCustomOptionText": "Ajouter \\{searchValue\\} en tant que nouvel environnement", + "xpack.apm.entitiesInventoryCallout.linklabel": "Essayez notre nouvel inventaire !", + "xpack.apm.entitiesInventoryCallout.linkTooltip": "Cacher ceci", + "xpack.apm.entityLink.eemGuide.description": "Désolé, nous ne pouvons pas vous donner plus de détails sur ce service pour le moment dû au motif suivant : {limitationsLink}.", + "xpack.apm.entityLink.eemGuide.description.link": "limitations du modèle d'entité d'Elastic", + "xpack.apm.entityLink.eemGuide.goBackButtonLabel": "Retour", + "xpack.apm.entityLink.eemGuide.title": "Service non pris en charge", "xpack.apm.environmentsSelectPlaceholder": "Sélectionner l'environnement", "xpack.apm.error.prompt.body": "Veuillez consulter la console de développeur de votre navigateur pour plus de détails.", "xpack.apm.error.prompt.title": "Désolé, une erreur s'est produite :(", "xpack.apm.errorCountAlert.name": "Seuil de nombre d'erreurs", - "xpack.apm.errorCountRuleType.errors": " erreurs", + "xpack.apm.errorCountRuleType.errors": "erreurs", "xpack.apm.errorGroup.chart.ocurrences": "Occurrences d'erreurs", "xpack.apm.errorGroup.tabs.exceptionStacktraceLabel": "Trace de pile d'exception", "xpack.apm.errorGroup.tabs.logStacktraceLabel": "Trace de pile des logs", @@ -10305,7 +11136,6 @@ "xpack.apm.errorGroupTopTransactions.loading": "Chargement...", "xpack.apm.errorGroupTopTransactions.noResults": "Aucune erreur trouvée associée à des transactions", "xpack.apm.errorGroupTopTransactions.title": "5 principales transactions affectées", - "xpack.apm.errorKeySelectCustomOptionText": "Ajouter \\{searchValue\\} comme nouvelle clé de groupe d'erreurs", "xpack.apm.errorOverview.treemap.dropdown.devices.subtitle": "Cet affichage sous forme de compartimentage permet de visualiser plus facilement et rapidement les appareils les plus affectés", "xpack.apm.errorOverview.treemap.dropdown.versions.subtitle": "Cet affichage sous forme de compartimentage permet de visualiser plus facilement et rapidement les versions les plus affectées.", "xpack.apm.errorOverview.treemap.subtitle": "Compartimentage {currentTreemap} affichant le nombre total et les plus affectés", @@ -10343,6 +11173,7 @@ "xpack.apm.failure_badge.tooltip": "event.outcome = échec", "xpack.apm.featureRegistry.apmFeatureName": "APM et expérience utilisateur", "xpack.apm.feedbackMenu.appName": "APM", + "xpack.apm.feedbackModal.body.thanks": "Merci d'avoir essayé notre nouvelle interface. Nous continuerons à l'améliorer, alors revenez souvent.", "xpack.apm.fetcher.error.status": "Erreur", "xpack.apm.fetcher.error.title": "Erreur lors de la récupération des ressources", "xpack.apm.fetcher.error.url": "URL", @@ -10505,7 +11336,7 @@ "xpack.apm.home.alertsMenu.alerts": "Alertes et règles", "xpack.apm.home.alertsMenu.createAnomalyAlert": "Créer une règle d'anomalie", "xpack.apm.home.alertsMenu.createThresholdAlert": "Créer une règle de seuil", - "xpack.apm.home.alertsMenu.errorCount": " Créer une règle de comptage des erreurs", + "xpack.apm.home.alertsMenu.errorCount": "Créer une règle de comptage des erreurs", "xpack.apm.home.alertsMenu.transactionDuration": "Latence", "xpack.apm.home.alertsMenu.transactionErrorRate": "Taux de transactions ayant échoué", "xpack.apm.home.alertsMenu.viewActiveAlerts": "Gérer les règles", @@ -10549,7 +11380,7 @@ "xpack.apm.jvmsTable.nonHeapMemoryColumnLabel": "Moy. segment de mémoire sans tas", "xpack.apm.jvmsTable.threadCountColumnLabel": "Nombre de threads max", "xpack.apm.keyValueFilterList.actionFilterLabel": "Filtrer par valeur", - "xpack.apm.kueryBar.placeholder": "Rechercher {event, select,\n transaction {des transactions}\n metric {des indicateurs}\n error {des erreurs}\n other {des transactions, des erreurs et des indicateurs}\n } (par ex. {queryExample})", + "xpack.apm.kueryBar.placeholder": "Rechercher {event, select, transaction {des transactions} metric {des indicateurs} error {des erreurs} other {des transactions, des erreurs et des indicateurs} } (p. ex. {queryExample})", "xpack.apm.labs": "Ateliers", "xpack.apm.labs.cancel": "Annuler", "xpack.apm.labs.description": "Essayez les fonctionnalités APM qui sont en version d'évaluation technique et en cours de progression.", @@ -10558,6 +11389,11 @@ "xpack.apm.latencyCorrelations.licenseCheckText": "Pour utiliser les corrélations de latence, vous devez disposer d'une licence Elastic Platinum. Elle vous permettra de découvrir quels champs sont corrélés à de faibles performances.", "xpack.apm.license.button": "Commencer l'essai", "xpack.apm.license.title": "Commencer un essai gratuit de 30 jours", + "xpack.apm.logErrorRate": "Taux d'erreur des logs", + "xpack.apm.logErrorRate.tooltip.description": "Taux de logs d'erreurs par minute observé pour un {serviceName} donné.", + "xpack.apm.logRate": "Taux du log", + "xpack.apm.logs.chart.logRate": "Taux de log", + "xpack.apm.logs.chart.logsErrorRate": "Taux d'erreur des logs", "xpack.apm.managedTable.errorMessage": "Impossible de récupérer", "xpack.apm.managedTable.loadingDescription": "Chargement…", "xpack.apm.metadata.help": "Comment ajouter des étiquettes et d'autres données", @@ -10618,19 +11454,24 @@ "xpack.apm.mobileServiceDetails.serviceMapTabLabel": "Carte des services", "xpack.apm.mobileServiceDetails.transactionsTabLabel": "Transactions", "xpack.apm.mobileServices.breadcrumb.title": "Services", + "xpack.apm.multiSignal.servicesTable.logErrorRate.tooltip.serviceNameLabel": "service.name", + "xpack.apm.multiSignal.servicesTable.logRate.tooltip.description": "Taux de logs par minute observé pour un {serviceName} donné.", + "xpack.apm.multiSignal.servicesTable.logRate.tooltip.serviceNameLabel": "service.name", + "xpack.apm.multiSignal.table.tooltip.formula": "Calcul de la formule :", "xpack.apm.navigation.apmSettingsTitle": "Paramètres", "xpack.apm.navigation.apmStorageExplorerTitle": "Explorateur de stockage", "xpack.apm.navigation.apmTutorialTitle": "Tutoriel", "xpack.apm.navigation.dependenciesTitle": "Dépendances", + "xpack.apm.navigation.rootTitle": "Applications", "xpack.apm.navigation.serviceGroupsTitle": "Groupes de services", "xpack.apm.navigation.serviceMapTitle": "Carte des services", - "xpack.apm.navigation.servicesTitle": "Services", + "xpack.apm.navigation.servicesTitle": "Inventaire de service", "xpack.apm.navigation.tracesTitle": "Traces", "xpack.apm.noDataConfig.addApmIntegrationButtonLabel": "Ajouter l'intégration APM", "xpack.apm.noDataConfig.addDataButtonLabel": "Ajouter des données", "xpack.apm.noDataConfig.solutionName": "Observabilité", "xpack.apm.notAvailableLabel": "S. O.", - "xpack.apm.observabilityAiAssistant.functions.registerGetApmDownstreamDependencies.descriptionForUser": "Obtenez les dépendances en aval (services ou back-ends non instrumentés) pour un \n service. Vous pouvez ainsi mapper le nom d'une dépendance en aval avec un service par le \n renvoi de span.destination.service.resource et de service.name. Utilisez cette fonction pour \n explorer plus avant si nécessaire.", + "xpack.apm.observabilityAiAssistant.functions.registerGetApmDownstreamDependencies.descriptionForUser": "Obtenez les dépendances en aval (services ou back-ends non instrumentés) pour un service. Vous pouvez ainsi mapper le nom d'une dépendance en aval avec un service par le renvoi de span.destination.service.resource et de service.name. Utilisez ceci pour explorer davantage, si nécessaire.", "xpack.apm.observabilityAiAssistant.functions.registerGetApmServicesList.descriptionForUser": "Obtenez la liste des services surveillés, leur statut d'intégrité et les alertes.", "xpack.apm.onboarding.agent.column.configSettings": "Paramètre de configuration", "xpack.apm.onboarding.agent.column.configValue": "Valeur de configuration", @@ -10663,12 +11504,12 @@ "xpack.apm.onboarding.django.install.title": "Installer l'agent APM", "xpack.apm.onboarding.djangoClient.configure.commands.addAgentComment": "Ajouter l'agent aux applications installées", "xpack.apm.onboarding.djangoClient.configure.commands.addTracingMiddlewareComment": "Ajoutez notre intergiciel de traçage pour envoyer des indicateurs de performance", - "xpack.apm.onboarding.dotNet.configureAgent.textPost": "Si vous ne transférez pas une instance `IConfiguration` à l'agent (par ex., pour les applications non ASP.NET Core) vous pouvez également configurer l'agent par le biais de variables d'environnement. \n Pour une utilisation avancée, consultez [the documentation]({documentationLink}), qui comprend notamment le guide de démarrage rapide pour [Profiler Auto instrumentation]({profilerLink}).", + "xpack.apm.onboarding.dotNet.configureAgent.textPost": "Si vous ne transférez pas une instance `IConfiguration` à l'agent (par ex., pour les applications non ASP.NET Core) vous pouvez également configurer l'agent par le biais de variables d'environnement. Pour une utilisation avancée, consultez [the documentation]({documentationLink}), qui comprend notamment le guide de démarrage rapide pour [Profiler Auto instrumentation]({profilerLink}).", "xpack.apm.onboarding.dotNet.configureAgent.title": "Exemple de fichier appsettings.json :", - "xpack.apm.onboarding.dotNet.configureApplication.textPost": "La transmission d'une instance `IConfiguration` est facultative mais si cette opération est effectuée, l'agent lira les paramètres de configuration depuis cette instance `IConfiguration` (par ex. à partir du fichier `appsettings.json`).", - "xpack.apm.onboarding.dotNet.configureApplication.textPre": "Si vous utilisez ASP.NET Core avec le package `Elastic.Apm.NetCoreAll`, appelez la méthode `UseAllElasticApm` dans la méthode \"Configure\" dans le fichier `Startup.cs`.", + "xpack.apm.onboarding.dotNet.configureApplication.textPost": "La transmission d'une instance `IConfiguration` est facultative mais si cette opération est effectuée, l'agent lira les paramètres de configuration depuis cette instance `IConfiguration` (par ex. à partir du fichier `appsettings.json`).", + "xpack.apm.onboarding.dotNet.configureApplication.textPre": "Si vous utilisez ASP.NET Core avec le package `Elastic.Apm.NetCoreAll`, appelez la méthode `UseAllElasticApm` dans la méthode `Configure` dans le fichier `Startup.cs`.", "xpack.apm.onboarding.dotNet.configureApplication.title": "Ajouter l'agent à l'application", - "xpack.apm.onboarding.dotNet.download.textPre": "Ajoutez le ou les packages d'agent depuis [NuGet]({allNuGetPackagesLink}) à votre application .NET. Plusieurs packages NuGet sont disponibles pour différents cas d'utilisation. \n\nPour une application ASP.NET Core avec Entity Framework Core, téléchargez le package [Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}). Ce package ajoutera automatiquement chaque composant d'agent à votre application. \n\n Si vous souhaitez minimiser les dépendances, vous pouvez utiliser le package [Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) uniquement pour le monitoring d'ASP.NET Core ou le package [Elastic.Apm.EfCore]({efCorePackageLink}) uniquement pour le monitoring d'Entity Framework Core. \n\n Si vous souhaitez seulement utiliser l'API d'agent publique pour l'instrumentation manuelle, utilisez le package [Elastic.Apm]({elasticApmPackageLink}).", + "xpack.apm.onboarding.dotNet.download.textPre": "Ajoutez le ou les packages d'agent depuis [NuGet]({allNuGetPackagesLink}) à votre application .NET. Plusieurs packages NuGet sont disponibles pour différents cas d'utilisation. Pour une application ASP.NET Core avec Entity Framework Core, téléchargez le package [Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}). Ce package ajoutera automatiquement chaque composant d'agent à votre application. Si vous souhaitez minimiser les dépendances, vous pouvez utiliser le package [Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) uniquement pour le monitoring d'ASP.NET Core ou le package [Elastic.Apm.EfCore]({efCorePackageLink}) uniquement pour le monitoring d'Entity Framework Core. Si vous souhaitez seulement utiliser l'API d'agent publique pour l'instrumentation manuelle, utilisez le package [Elastic.Apm]({elasticApmPackageLink}).", "xpack.apm.onboarding.dotNet.download.title": "Télécharger l'agent APM", "xpack.apm.onboarding.dotnetClient.createConfig.commands.defaultServiceName": "La valeur par défaut est l'assemblage d'entrée de l'application.", "xpack.apm.onboarding.flask.configure.textPost": "Consultez la [documentation]({documentationLink}) pour une utilisation avancée.", @@ -10691,26 +11532,26 @@ "xpack.apm.onboarding.goClient.configure.commands.initializeUsingEnvironmentVariablesComment": "Initialisez à l'aide des variables d'environnement :", "xpack.apm.onboarding.goClient.configure.commands.usedExecutableNameComment": "En l'absence de spécification, le nom de l'exécutable est utilisé.", "xpack.apm.onboarding.introduction.imageAltDescription": "Capture d'écran du tableau de bord principal.", - "xpack.apm.onboarding.java.download.textPre": "Téléchargez le fichier jar de l'agent depuis [Maven Central]({mavenCentralLink}). N'ajoutez **pas** l'agent comme dépendance de votre application.", + "xpack.apm.onboarding.java.download.textPre": "Téléchargez le fichier jar de l'agent depuis [Maven Central]({mavenCentralLink}). N'ajoutez **pas** l'agent comme dépendance de votre application.", "xpack.apm.onboarding.java.download.title": "Télécharger l'agent APM", "xpack.apm.onboarding.java.startApplication.textPost": "Consultez la [documentation]({documentationLink}) pour découvrir les options de configuration et l'utilisation avancée.", - "xpack.apm.onboarding.java.startApplication.textPre": "Ajoutez l'indicateur `-javaagent` et configurez l'agent avec les propriétés du système.\n\n * Définir le nom de service requis (caractères autorisés : a-z, A-Z, 0-9, -, _ et espace)\n * Définir l'URL personnalisée du serveur APM (par défaut : {customApmServerUrl})\n * Définir le token secret du serveur APM\n * Définir l'environnement de service\n * Définir le package de base de votre application", + "xpack.apm.onboarding.java.startApplication.textPre": "Ajoutez l'indicateur `-javaagent` et configurez l'agent avec les propriétés du système. * Définir le nom de service requis (caractères autorisés : a-z, A-Z, 0-9, -, _ et espace) * * Définir l'URL personnalisée du serveur APM (par défaut : {customApmServerUrl}) * Définir le jeton secret du serveur APM * Définir l'environnement de service * Définir le package de base de votre application", "xpack.apm.onboarding.java.startApplication.title": "Lancer votre application avec l'indicateur javaagent", "xpack.apm.onboarding.node.configure.textPost": "Consultez [the documentation]({documentationLink}) pour une utilisation avancée, notamment pour connaître l'utilisation avec [Babel/ES Modules]({babelEsModulesLink}).", - "xpack.apm.onboarding.node.configure.textPre": "Les agents sont des bibliothèques exécutées dans les processus de votre application. Les services APM sont créés par programmation à partir du `serviceName`. Cet agent prend en charge de nombreux frameworks, mais peut également être utilisé avec votre pile personnalisée.", + "xpack.apm.onboarding.node.configure.textPre": "Les agents sont des bibliothèques exécutées dans les processus de votre application. Les services APM sont créés par programmation à partir du `serviceName`. Cet agent prend en charge de nombreux frameworks, mais peut également être utilisé avec votre pile personnalisée.", "xpack.apm.onboarding.node.configure.title": "Configurer l'agent", "xpack.apm.onboarding.node.install.textPre": "Installez l'agent APM pour Node.js comme dépendance de votre application.", "xpack.apm.onboarding.node.install.title": "Installer l'agent APM", "xpack.apm.onboarding.nodeClient.configure.commands.addThisToTheFileTopComment": "Ajoutez ceci tout en haut du premier fichier chargé dans votre application", "xpack.apm.onboarding.nodeClient.createConfig.commands.serviceName": "Remplace le nom de service dans package.json.", "xpack.apm.onboarding.otel.column.value.copyIconText": "Copier dans le presse-papiers", - "xpack.apm.onboarding.otel.configureAgent.textPost": "Consultez la [documentation]({documentationLink}) pour découvrir les options de configuration et l'utilisation avancée.\n\n", + "xpack.apm.onboarding.otel.configureAgent.textPost": "Consultez la [documentation]({documentationLink}) pour découvrir les options de configuration et l'utilisation avancée.", "xpack.apm.onboarding.otel.configureAgent.textPre": "Spécifiez les paramètres OpenTelemetry suivants dans le cadre du démarrage de votre application. Notez que les SDK OpenTelemetry exigent du code de démarrage en plus de ces paramètres de configuration. Pour plus de détails, consultez la [documentation OpenTelemetry Elastic]({openTelemetryDocumentationLink}) et les [guides d'instrumentation OpenTelemetry]({openTelemetryInstrumentationLink}).", "xpack.apm.onboarding.otel.configureAgent.title": "Configurer OpenTelemetry dans votre application", "xpack.apm.onboarding.otel.download.textPre": "Consultez les [guides d'instrumentation OpenTelemetry]({openTelemetryInstrumentationLink}) pour télécharger l'agent ou le SDK OpenTelemetry pour votre langage.", "xpack.apm.onboarding.otel.download.title": "Télécharger l’agent APM OpenTelemetry ou le SDK", "xpack.apm.onboarding.php.Configure the agent.textPre": "APM se lance automatiquement au démarrage de l'application. Configurez l'agent soit depuis le fichier `php.ini` :", - "xpack.apm.onboarding.php.configureAgent.textPost": "Consultez la [documentation]({documentationLink}) pour découvrir les options de configuration et l'utilisation avancée.\n\n", + "xpack.apm.onboarding.php.configureAgent.textPost": "Consultez la [documentation]({documentationLink}) pour découvrir les options de configuration et l'utilisation avancée.", "xpack.apm.onboarding.php.configureAgent.title": "Configurer l'agent", "xpack.apm.onboarding.php.download.textPre": "Téléchargez le package correspondant à votre plateforme depuis [GitHub releases]({githubReleasesLink}).", "xpack.apm.onboarding.php.download.title": "Télécharger l'agent APM", @@ -10719,7 +11560,7 @@ "xpack.apm.onboarding.php.installPackage.title": "Installer le package téléchargé", "xpack.apm.onboarding.rack.configure.commands.optionalComment": "facultatif, la valeur par défaut est config/elastic_apm.yml", "xpack.apm.onboarding.rack.configure.commands.requiredComment": "requis", - "xpack.apm.onboarding.rack.configure.textPost": "Consultez la [documentation]({documentationLink}) pour découvrir les options de configuration et l'utilisation avancée.\n\n", + "xpack.apm.onboarding.rack.configure.textPost": "Consultez la [documentation]({documentationLink}) pour découvrir les options de configuration et l'utilisation avancée.", "xpack.apm.onboarding.rack.configure.textPre": "Pour Rack, ou un framework compatible (par ex., Sinatra), intégrez l'intergiciel à votre application et démarrez l'agent.", "xpack.apm.onboarding.rack.configure.title": "Configurer l'agent", "xpack.apm.onboarding.rack.createConfig.textPre": "Créez un fichier config {configFile} :", @@ -10727,7 +11568,7 @@ "xpack.apm.onboarding.rack.install.textPre": "Ajoutez l'agent à votre Gemfile.", "xpack.apm.onboarding.rack.install.title": "Installer l'agent APM", "xpack.apm.onboarding.rackClient.createConfig.commands.defaultsToTheNameOfRackAppClassComment": "La valeur par défaut est le nom de la classe de votre application Rack.", - "xpack.apm.onboarding.rails.configure.textPost": "Consultez la [documentation]({documentationLink}) pour découvrir les options de configuration et l'utilisation avancée.\n\n", + "xpack.apm.onboarding.rails.configure.textPost": "Consultez la [documentation]({documentationLink}) pour découvrir les options de configuration et l'utilisation avancée.", "xpack.apm.onboarding.rails.configure.textPre": "APM se lance automatiquement au démarrage de l'application. Configurer l'agent, en créant le fichier config {configFile}", "xpack.apm.onboarding.rails.configure.title": "Configurer l'agent", "xpack.apm.onboarding.rails.install.textPre": "Ajoutez l'agent à votre Gemfile.", @@ -10738,6 +11579,8 @@ "xpack.apm.onboarding.shared_clients.configure.commands.serverUrlHint": "Définir l'URL personnalisée du serveur APM (par défaut : {defaultApmServerUrl}). L'URL doit être complète et inclure le protocole (http ou https) et le port.", "xpack.apm.onboarding.shared_clients.configure.commands.serviceEnvironmentHint": "Le nom de l'environnement dans lequel ce service est déployé, par exemple \"production\" ou \"test\". Les environnements vous permettent de facilement filtrer les données à un niveau global dans l'interface utilisateur APM. Il est important de garantir la cohérence des noms d'environnements entre les différents agents.", "xpack.apm.onboarding.shared_clients.configure.commands.serviceNameHint": "Le nom de service est le filtre principal dans l'interface utilisateur APM et est utilisé pour regrouper les erreurs et suivre les données ensemble. Caractères autorisés : a-z, A-Z, 0-9, -, _ et espace.", + "xpack.apm.onboarding.specProvider.learnMoreAriaLabel": "En savoir plus sur APM", + "xpack.apm.onboarding.specProvider.learnMoreLabel": "En savoir plus", "xpack.apm.onboarding.specProvider.longDescription": "Le monitoring des performances applicatives (APM) collecte les indicateurs et les erreurs de performance approfondies depuis votre application. Cela vous permet de monitorer les performances de milliers d'applications en temps réel. {learnMoreLink}.", "xpack.apm.percentOfParent": "({value} de {parentType, select, transaction { transaction } trace {trace} other {parentType inconnu} })", "xpack.apm.profiling.callout.description": "Universal Profiling fournit une visibilité sans précédent du code au milieu du comportement en cours d'exécution de toutes les applications. La fonctionnalité profile chaque ligne de code chez le ou les hôtes qui exécutent vos services, y compris votre code applicatif, le kernel et même les bibliothèque tierces.", @@ -10872,6 +11715,7 @@ "xpack.apm.serviceGroups.groupDetailsForm.description.optional": "Facultatif", "xpack.apm.serviceGroups.groupDetailsForm.edit.title": "Modifier un groupe", "xpack.apm.serviceGroups.groupDetailsForm.invalidColorError": "Veuillez fournir une valeur HEX de couleur valide", + "xpack.apm.serviceGroups.groupDetailsForm.invalidNameError": "Veuillez fournir une valeur de nom valide", "xpack.apm.serviceGroups.groupDetailsForm.name": "Nom", "xpack.apm.serviceGroups.groupDetailsForm.selectServices": "Sélectionner des services", "xpack.apm.serviceGroups.groupsCount": "{servicesCount} {servicesCount, plural, =0 {groupe} one {groupe} other {groupes}}", @@ -10911,13 +11755,13 @@ "xpack.apm.serviceIcons.serverless": "Sans serveur", "xpack.apm.serviceIcons.service": "Service", "xpack.apm.serviceIcons.serviceDetails.cloud.architecture": "Architecture", - "xpack.apm.serviceIcons.serviceDetails.cloud.availabilityZoneLabel": "{zones, plural, =0 {Zone de disponibilité} one {Zone de disponibilité} other {Zones de disponibilité}} ", - "xpack.apm.serviceIcons.serviceDetails.cloud.faasTriggerTypeLabel": "{triggerTypes, plural, =0 {Type de déclencheur} one {Type de déclencheur} other {Types de déclencheurs}} ", - "xpack.apm.serviceIcons.serviceDetails.cloud.functionNameLabel": "{functionNames, plural, =0 {Nom de fonction} one {Nom de fonction} other {Noms de fonction}} ", - "xpack.apm.serviceIcons.serviceDetails.cloud.machineTypesLabel": "{machineTypes, plural, =0{Type de machine} one {Type de machine} other {Types de machines}} ", + "xpack.apm.serviceIcons.serviceDetails.cloud.availabilityZoneLabel": "{zones, plural, =0 {Zone de disponibilité} one {Zone de disponibilité} other {Zones de disponibilité}}", + "xpack.apm.serviceIcons.serviceDetails.cloud.faasTriggerTypeLabel": "{triggerTypes, plural, =0 {Type de déclencheur} one {Type de déclencheur} other {Types de déclencheurs}}", + "xpack.apm.serviceIcons.serviceDetails.cloud.functionNameLabel": "{functionNames, plural, =0 {Nom de fonction} one {Nom de fonction} other {Noms de fonction}}", + "xpack.apm.serviceIcons.serviceDetails.cloud.machineTypesLabel": "{machineTypes, plural, =0{Type de machine} one {Type de machine} other {Types de machines}}", "xpack.apm.serviceIcons.serviceDetails.cloud.projectIdLabel": "ID de projet", "xpack.apm.serviceIcons.serviceDetails.cloud.providerLabel": "Fournisseur cloud", - "xpack.apm.serviceIcons.serviceDetails.cloud.regionLabel": "{regions, plural, =0 {Region} one {Région} other {Régions}} ", + "xpack.apm.serviceIcons.serviceDetails.cloud.regionLabel": "{regions, plural, =0 {Region} one {Région} other {Régions}}", "xpack.apm.serviceIcons.serviceDetails.cloud.serviceNameLabel": "Service Cloud", "xpack.apm.serviceIcons.serviceDetails.container.image.name": "Images de conteneurs", "xpack.apm.serviceIcons.serviceDetails.container.os.label": "Système d'exploitation", @@ -10968,7 +11812,6 @@ "xpack.apm.serviceMap.zoomIn": "Zoom avant", "xpack.apm.serviceMap.zoomOut": "Zoom arrière", "xpack.apm.serviceMetrics.loading": "Chargement des indicateurs", - "xpack.apm.serviceNamesSelectCustomOptionText": "Ajouter \\{searchValue\\} en tant que nouveau nom de service", "xpack.apm.serviceNamesSelectPlaceholder": "Sélectionner le nom du service", "xpack.apm.serviceNodeMetrics.containerId": "ID de conteneur", "xpack.apm.serviceNodeMetrics.host": "Hôte", @@ -11061,10 +11904,24 @@ "xpack.apm.servicesTable.tooltip.metricsExplanation": "Les indicateurs du services sont agrégés sur le type de transaction, qui peut être une requête ou un chargement de page. Si ni l'un ni l'autre n'existent, les indicateurs sont agrégés sur le type de transaction disponible en premier.", "xpack.apm.servicesTable.transactionColumnLabel": "Type de transaction", "xpack.apm.servicesTable.transactionErrorRate": "Taux de transactions ayant échoué", + "xpack.apm.serviceTabEmptyState.dependenciesContent": "Visualisez les dépendances de votre service sur les services internes et tiers en instrumentant avec APM.", + "xpack.apm.serviceTabEmptyState.dependenciesTitle": "Comprendre les dépendances de votre service", + "xpack.apm.serviceTabEmptyState.errorGroupOverviewContent": "Analysez les erreurs jusqu'à la transaction spécifique pour identifier les erreurs spécifiques au sein de votre service.", + "xpack.apm.serviceTabEmptyState.errorGroupOverviewTitle": "Identifier les erreurs de transaction liées à vos applications", + "xpack.apm.serviceTabEmptyState.infrastructureContent": "Résolvez les problèmes de service en visualisant l'infrastructure sur laquelle votre service s'exécute.", + "xpack.apm.serviceTabEmptyState.infrastructureTitle": "Comprendre sur quoi s'exécute votre service", + "xpack.apm.serviceTabEmptyState.metricsContent": "Collectez des indicateurs tels que l'utilisation du processeur et de la mémoire pour identifier les goulots d'étranglement des performances qui pourraient affecter vos utilisateurs.", + "xpack.apm.serviceTabEmptyState.metricsTitle": "Afficher les indicateurs clés de votre application", + "xpack.apm.serviceTabEmptyState.overviewContent": "Comprendre les performances, les relations et les dépendances de vos applications en instrumentant avec APM.", + "xpack.apm.serviceTabEmptyState.overviewTitle": "Détectez et résolvez les problèmes plus rapidement grâce à une meilleure visibilité sur votre application", + "xpack.apm.serviceTabEmptyState.serviceMapContent": "Consultez en un coup d'œil les dépendances de vos services pour vous aider à identifier celles susceptibles d'affecter votre service.", + "xpack.apm.serviceTabEmptyState.serviceMapTitle": "Visualiser les dépendances reliant vos services", + "xpack.apm.serviceTabEmptyState.transactionsContent": "Résolvez les problèmes liés aux performances de votre service en analysant la latence, le débit et les erreurs jusqu'à la transaction spécifique.", + "xpack.apm.serviceTabEmptyState.transactionsTitle": "Résoudre les problèmes liés à la latence, au débit et aux erreurs", "xpack.apm.settings.agentConfig": "Configuration de l'agent", "xpack.apm.settings.agentConfig.createConfigButton.tooltip": "Vous ne disposez pas d'autorisations pour créer des configurations d'agent", "xpack.apm.settings.agentConfig.descriptionText": "Affinez votre configuration d'agent depuis l'application APM. Les modifications sont automatiquement propagées à vos agents APM, ce qui vous évite d'effectuer un redéploiement.", - "xpack.apm.settings.agentConfiguration.all.option.calloutTitle": "Ce changement de configuration aura un impact sur tous les services, à l'exception de ceux qui utilisent un agent OpenTelemetry. ", + "xpack.apm.settings.agentConfiguration.all.option.calloutTitle": "Ce changement de configuration aura un impact sur tous les services, à l'exception de ceux qui utilisent un agent OpenTelemetry.", "xpack.apm.settings.agentConfiguration.service.otel.error": "Les services sélectionnés utilisent un agent OpenTelemetry, qui n'est pas pris en charge", "xpack.apm.settings.agentExplorer": "Explorateur d'agent", "xpack.apm.settings.agentExplorer.descriptionText": "L'explorateur d'agent fournit un inventaire des agents déployés et des détails les concernant.", @@ -11099,6 +11956,7 @@ "xpack.apm.settings.agentKeys.emptyPromptTitle": "Créer votre première clé", "xpack.apm.settings.agentKeys.invalidate.failed": "Erreur lors de la suppression de la clé de l'agent APM \"{name}\"", "xpack.apm.settings.agentKeys.invalidate.succeeded": "Suppression de la clé de l'agent APM \"{name}\"", + "xpack.apm.settings.agentKeys.noPermissionCreateAgentKeyTooltipLabel": "Votre rôle d'utilisateur ne dispose pas d'autorisations pour créer des clés d'agent.", "xpack.apm.settings.agentKeys.noPermissionToManagelApiKeysDescription": "Contactez votre administrateur système", "xpack.apm.settings.agentKeys.noPermissionToManagelApiKeysTitle": "Vous devez disposer d'une autorisation pour gérer les clés d'API", "xpack.apm.settings.agentKeys.table.creationColumnName": "Créé", @@ -11131,6 +11989,7 @@ "xpack.apm.settings.anomalyDetection.jobList.mlDescriptionText": "Pour ajouter la détection des anomalies à un nouvel environnement, créez une tâche de Machine Learning. Vous pouvez gérer les tâches de Machine Learning existantes dans {mlJobsLink}.", "xpack.apm.settings.anomalyDetection.jobList.mlDescriptionText.mlJobsLinkText": "Machine Learning", "xpack.apm.settings.anomalyDetection.jobList.mlJobLinkText": "Gérer la tâche", + "xpack.apm.settings.anomalyDetection.jobList.noPermissionAddEnvironmentsTooltipLabel": "Votre rôle d'utilisateur ne dispose pas d'autorisations pour créer des tâches", "xpack.apm.settings.anomalyDetection.jobList.okStatusLabel": "OK", "xpack.apm.settings.anomalyDetection.jobList.openAnomalyExplorerrLinkText": "Ouvrir dans Anomaly Explorer", "xpack.apm.settings.anomalyDetection.jobList.showLegacyJobsCheckboxText": "Afficher les tâches héritées", @@ -11338,6 +12197,8 @@ "xpack.apm.storageExplorer.table.samplingColumnName": "Taux d’échantillonnage", "xpack.apm.storageExplorer.table.serviceColumnName": "Service", "xpack.apm.storageExplorerLinkLabel": "Explorateur de stockage", + "xpack.apm.subFeatureRegistry.modifySettings": "Possibilité de modifier les paramètres", + "xpack.apm.subFeatureRegistry.settings": "Paramètres", "xpack.apm.technicalPreviewBadgeDescription": "Cette fonctionnalité est en version d'évaluation technique et pourra être modifiée ou retirée complètement dans une future version. Elastic s'efforcera de corriger tout problème, mais les fonctionnalités des versions d'évaluation technique ne sont pas soumises aux SLA de support des fonctionnalités officielles en disponibilité générale.", "xpack.apm.technicalPreviewBadgeLabel": "Version d'évaluation technique", "xpack.apm.timeComparison.label": "Comparaison", @@ -11351,6 +12212,7 @@ "xpack.apm.traceExplorer.appName": "APM", "xpack.apm.traceExplorer.criticalPathTab": "Chemin critique agrégé", "xpack.apm.traceExplorer.waterfallTab": "Cascade", + "xpack.apm.traceLink.fetchingTraceLabel": "Récupération des traces...", "xpack.apm.traceOverview.topTracesTab": "Premières traces", "xpack.apm.traceOverview.traceExplorerTab": "Explorer", "xpack.apm.traceSearchBox.refreshButton": "Recherche", @@ -11482,7 +12344,6 @@ "xpack.apm.transactionsTable.tableSearch.placeholder": "Rechercher des transactions par nom", "xpack.apm.transactionsTable.title": "Transactions", "xpack.apm.transactionsTableColumnName.alertsColumnLabel": "Alertes actives", - "xpack.apm.transactionTypesSelectCustomOptionText": "Ajouter \\{searchValue\\} en tant que nouveau type de transaction", "xpack.apm.transactionTypesSelectPlaceholder": "Sélectionner le type de transaction", "xpack.apm.tryItButton.euiButtonIcon.admin": "Veuillez référer à votre administrateur pour rendre cette fonctionnalité {featureEnabled}.", "xpack.apm.tryItButton.euiButtonIcon.admin.off": "désactivé", @@ -11504,7 +12365,7 @@ "xpack.apm.tutorial.apmAgents.statusCheck.text": "Vérifiez que votre application est en cours d'exécution et que les agents envoient les données.", "xpack.apm.tutorial.apmAgents.statusCheck.title": "Statut de l'agent", "xpack.apm.tutorial.apmAgents.title": "Agents APM", - "xpack.apm.tutorial.apmServer.callOut.message": "Assurez-vous de mettre à jour votre serveur APM vers la version 7.0 ou supérieure. Vous pouvez également migrer vos données 6.x à l'aide de l'assistant de migration disponible dans la section de gestion de Kibana.", + "xpack.apm.tutorial.apmServer.callOut.message": "Assurez-vous de mettre à jour votre serveur APM vers la version 7.0 ou supérieure. Vous pouvez également migrer vos données 6.x à l'aide de l'assistant de migration disponible dans la section de gestion de Kibana.", "xpack.apm.tutorial.apmServer.callOut.title": "Important : mise à niveau vers la version 7.0 ou supérieure", "xpack.apm.tutorial.apmServer.fleet.apmIntegration.button": "Intégration APM", "xpack.apm.tutorial.apmServer.fleet.apmIntegration.description": "Fleet vous permet de gérer de manière centralisée les agents Elastic qui exécutent l'intégration APM. L'option par défaut consiste à installer un serveur Fleet sur un hôte dédié. Pour les configurations sans hôte dédié, nous vous recommandons de suivre les instructions pour installer le serveur APM autonome pour votre système d'exploitation en sélectionnant l'onglet correspondant ci-dessus.", @@ -11532,13 +12393,13 @@ "xpack.apm.tutorial.djangoClient.configure.title": "Configurer l'agent", "xpack.apm.tutorial.djangoClient.install.textPre": "Installez l'agent APM pour Python en tant que dépendance.", "xpack.apm.tutorial.djangoClient.install.title": "Installer l'agent APM", - "xpack.apm.tutorial.dotNetClient.configureAgent.textPost": "Si vous ne transférez pas une instance `IConfiguration` à l'agent (par ex., pour les applications non ASP.NET Core) vous pouvez également configurer l'agent par le biais de variables d'environnement. \n Pour une utilisation avancée, consultez [the documentation]({documentationLink}), qui comprend notamment le guide de démarrage rapide pour [Profiler Auto instrumentation]({profilerLink}).", + "xpack.apm.tutorial.dotNetClient.configureAgent.textPost": "Si vous ne transférez pas une instance `IConfiguration` à l'agent (par ex., pour les applications non ASP.NET Core) vous pouvez également configurer l'agent par le biais de variables d'environnement. Pour une utilisation avancée, consultez [the documentation]({documentationLink}), qui comprend notamment le guide de démarrage rapide pour [Profiler Auto instrumentation]({profilerLink}).", "xpack.apm.tutorial.dotNetClient.configureAgent.title": "Exemple de fichier appsettings.json :", - "xpack.apm.tutorial.dotNetClient.configureApplication.textPost": "La transmission d'une instance `IConfiguration` est facultative mais si cette opération est effectuée, l'agent lira les paramètres de configuration depuis cette instance `IConfiguration` (par ex. à partir du fichier `appsettings.json`).", - "xpack.apm.tutorial.dotNetClient.configureApplication.textPre": "Si vous utilisez ASP.NET Core avec le package `Elastic.Apm.NetCoreAll`, appelez la méthode `UseAllElasticApm` dans la méthode \"Configure\" dans le fichier `Startup.cs`.", + "xpack.apm.tutorial.dotNetClient.configureApplication.textPost": "La transmission d'une instance `IConfiguration` est facultative mais si cette opération est effectuée, l'agent lira les paramètres de configuration depuis cette instance `IConfiguration` (par ex. à partir du fichier `appsettings.json`).", + "xpack.apm.tutorial.dotNetClient.configureApplication.textPre": "Si vous utilisez ASP.NET Core avec le package `Elastic.Apm.NetCoreAll`, appelez la méthode `UseAllElasticApm` dans la méthode `Configure` dans le fichier `Startup.cs`.", "xpack.apm.tutorial.dotNetClient.configureApplication.title": "Ajouter l'agent à l'application", "xpack.apm.tutorial.dotnetClient.createConfig.commands.defaultServiceName": "La valeur par défaut est l'assemblage d'entrée de l'application.", - "xpack.apm.tutorial.dotNetClient.download.textPre": "Ajoutez le ou les packages d'agent depuis [NuGet]({allNuGetPackagesLink}) à votre application .NET. Plusieurs packages NuGet sont disponibles pour différents cas d'utilisation. \n\nPour une application ASP.NET Core avec Entity Framework Core, téléchargez le package [Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}). Ce package ajoutera automatiquement chaque composant d'agent à votre application. \n\n Si vous souhaitez minimiser les dépendances, vous pouvez utiliser le package [Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) uniquement pour le monitoring d'ASP.NET Core ou le package [Elastic.Apm.EfCore]({efCorePackageLink}) uniquement pour le monitoring d'Entity Framework Core. \n\n Si vous souhaitez seulement utiliser l'API d'agent publique pour l'instrumentation manuelle, utilisez le package [Elastic.Apm]({elasticApmPackageLink}).", + "xpack.apm.tutorial.dotNetClient.download.textPre": "Ajoutez le ou les packages d'agent depuis [NuGet]({allNuGetPackagesLink}) à votre application .NET. Plusieurs packages NuGet sont disponibles pour différents cas d'utilisation. Pour une application ASP.NET Core avec Entity Framework Core, téléchargez le package [Elastic.Apm.NetCoreAll]({netCoreAllApmPackageLink}). Ce package ajoutera automatiquement chaque composant d'agent à votre application. Si vous souhaitez minimiser les dépendances, vous pouvez utiliser le package [Elastic.Apm.AspNetCore]({aspNetCorePackageLink}) uniquement pour le monitoring d'ASP.NET Core ou le package [Elastic.Apm.EfCore]({efCorePackageLink}) uniquement pour le monitoring d'Entity Framework Core. Si vous souhaitez seulement utiliser l'API d'agent publique pour l'instrumentation manuelle, utilisez le package [Elastic.Apm]({elasticApmPackageLink}).", "xpack.apm.tutorial.dotNetClient.download.title": "Télécharger l'agent APM", "xpack.apm.tutorial.downloadServer.title": "Télécharger et décompresser le serveur APM", "xpack.apm.tutorial.downloadServerRpm": "Vous cherchez les packages aarch64 ? Consultez la [Download page]({downloadPageLink}).", @@ -11569,13 +12430,13 @@ "xpack.apm.tutorial.javaClient.download.textPre": "Téléchargez le fichier jar de l'agent depuis [Maven Central]({mavenCentralLink}). N'ajoutez **pas** l'agent comme dépendance de votre application.", "xpack.apm.tutorial.javaClient.download.title": "Télécharger l'agent APM", "xpack.apm.tutorial.javaClient.startApplication.textPost": "Consultez la [documentation]({documentationLink}) pour découvrir les options de configuration et l'utilisation avancée.", - "xpack.apm.tutorial.javaClient.startApplication.textPre": "Ajoutez l'indicateur `-javaagent` et configurez l'agent avec les propriétés du système.\n\n * Définir le nom de service requis (caractères autorisés : a-z, A-Z, 0-9, -, _ et espace)\n * Définir l'URL personnalisée du serveur APM (par défaut : {customApmServerUrl})\n * Définir le token secret du serveur APM\n * Définir l'environnement de service\n * Définir le package de base de votre application", + "xpack.apm.tutorial.javaClient.startApplication.textPre": "Ajoutez l'indicateur `-javaagent` et configurez l'agent avec les propriétés du système. * Définir le nom de service requis (caractères autorisés : a-z, A-Z, 0-9, -, _ et espace) * * Définir l'URL personnalisée du serveur APM (par défaut : {customApmServerUrl}) * Définir le jeton secret du serveur APM * Définir l'environnement de service * Définir le package de base de votre application", "xpack.apm.tutorial.javaClient.startApplication.title": "Lancer votre application avec l'indicateur javaagent", "xpack.apm.tutorial.jsClient.enableRealUserMonitoring.textPre": "Le serveur APM désactive la prise en charge du RUM par défaut. Consultez la [documentation]({documentationLink}) pour obtenir des détails sur l'activation de la prise en charge du RUM. Lorsque vous utilisez l'intégration APM avec Fleet, le support RUM est automatiquement activé.", "xpack.apm.tutorial.jsClient.enableRealUserMonitoring.title": "Activer la prise en charge du Real User Monitoring (monitoring des utilisateurs réels) dans le serveur APM", "xpack.apm.tutorial.jsClient.installDependency.commands.setServiceVersionComment": "Définir la version de service (requis pour la fonctionnalité source map)", "xpack.apm.tutorial.jsClient.installDependency.textPost": "Les intégrations de framework, tel que React ou Angular, ont des dépendances personnalisées. Consultez la [integration documentation]({docLink}) pour plus d'informations.", - "xpack.apm.tutorial.jsClient.installDependency.textPre": "Vous pouvez installer l'Agent comme dépendance de votre application avec `npm install @elastic/apm-rum --save`.\n\nVous pouvez ensuite initialiser l'agent et le configurer dans votre application de cette façon :", + "xpack.apm.tutorial.jsClient.installDependency.textPre": "Vous pouvez installer l'Agent comme dépendance de votre application avec `npm install @elastic/apm-rum --save`. Vous pouvez ensuite initialiser l'agent et le configurer dans votre application de cette façon :", "xpack.apm.tutorial.jsClient.installDependency.title": "Configurer l'agent comme dépendance", "xpack.apm.tutorial.jsClient.scriptTags.textPre": "Vous pouvez également utiliser les balises Script pour configurer l'agent. Ajoutez un indicateur `